Skip to content

Commit 362c7d8

Browse files
authored
Merge pull request #15365 from rudkx/join-even-more
Improve type join for function types.
2 parents 7e797a1 + 994c2d1 commit 362c7d8

File tree

4 files changed

+95
-15
lines changed

4 files changed

+95
-15
lines changed

lib/AST/TypeJoinMeet.cpp

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ struct TypeJoin : CanTypeVisitor<TypeJoin, CanType> {
3838
// implementation.
3939
CanType Unimplemented;
4040

41+
// Always null. Used as a marker for places where there is no join
42+
// of two types in our type system.
43+
CanType Nonexistent;
44+
4145
// For convenience, TheAnyType from ASTContext;
4246
CanType TheAnyType;
4347

@@ -98,14 +102,13 @@ struct TypeJoin : CanTypeVisitor<TypeJoin, CanType> {
98102
if (second->getOptionalObjectType())
99103
return TypeJoin(first).visit(second);
100104

101-
// Likewise, rather than making every visitor deal with Any, just
102-
// handle it here.
103-
// join with Any is always Any
105+
// Likewise, rather than making every visitor deal with Any,
106+
// always dispatch to the protocol composition side of the join.
104107
if (first->isAny())
105-
return first;
108+
return TypeJoin(second).visit(first);
106109

107110
if (second->isAny())
108-
return second;
111+
return TypeJoin(first).visit(second);
109112

110113
// Otherwise the first type might be an optional (or not), so
111114
// dispatch there.
@@ -301,14 +304,23 @@ CanType TypeJoin::visitDependentMemberType(CanType second) {
301304
CanType TypeJoin::visitFunctionType(CanType second) {
302305
assert(First != second);
303306

304-
if (First->getKind() != second->getKind())
305-
return TheAnyType;
307+
auto secondFnTy = second->castTo<FunctionType>();
308+
309+
if (First->getKind() != second->getKind()) {
310+
if (secondFnTy->getExtInfo().isNoEscape()) {
311+
return Nonexistent;
312+
} else {
313+
return TheAnyType;
314+
}
315+
}
306316

307317
auto firstFnTy = First->castTo<FunctionType>();
308-
auto secondFnTy = second->castTo<FunctionType>();
318+
319+
auto firstExtInfo = firstFnTy->getExtInfo();
320+
auto secondExtInfo = secondFnTy->getExtInfo();
309321

310322
// FIXME: Properly handle these attributes.
311-
if (firstFnTy->getExtInfo() != secondFnTy->getExtInfo())
323+
if (firstExtInfo.withNoEscape(false) != secondExtInfo.withNoEscape(false))
312324
return Unimplemented;
313325

314326
// FIXME: Properly compute parameter types from getParams().
@@ -323,8 +335,12 @@ CanType TypeJoin::visitFunctionType(CanType second) {
323335
if (!result)
324336
return Unimplemented;
325337

338+
auto extInfo = firstExtInfo;
339+
if (secondFnTy->getExtInfo().isNoEscape())
340+
extInfo = extInfo.withNoEscape(true);
341+
326342
return FunctionType::get(firstFnTy->getInput(), result,
327-
firstFnTy->getExtInfo())->getCanonicalType();
343+
extInfo)->getCanonicalType();
328344
}
329345

330346
CanType TypeJoin::visitGenericFunctionType(CanType second) {
@@ -337,8 +353,13 @@ CanType TypeJoin::visitGenericFunctionType(CanType second) {
337353
}
338354

339355
CanType TypeJoin::visitProtocolCompositionType(CanType second) {
340-
if (second->isAny())
356+
if (second->isAny()) {
357+
auto *fnTy = First->getAs<AnyFunctionType>();
358+
if (fnTy && fnTy->getExtInfo().isNoEscape())
359+
return Nonexistent;
360+
341361
return second;
362+
}
342363

343364
return Unimplemented;
344365
}

lib/Sema/CSGen.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2954,7 +2954,12 @@ namespace {
29542954
llvm_unreachable("found KeyPathDotExpr in CSGen");
29552955
}
29562956

2957-
enum class TypeOperation { None, Join, JoinInout, JoinMeta };
2957+
enum class TypeOperation { None,
2958+
Join,
2959+
JoinInout,
2960+
JoinMeta,
2961+
JoinNonexistent
2962+
};
29582963

29592964
static TypeOperation getTypeOperation(UnresolvedDotExpr *UDE,
29602965
ASTContext &Context) {
@@ -2970,6 +2975,7 @@ namespace {
29702975
.Case("type_join", TypeOperation::Join)
29712976
.Case("type_join_inout", TypeOperation::JoinInout)
29722977
.Case("type_join_meta", TypeOperation::JoinMeta)
2978+
.Case("type_join_nonexistent", TypeOperation::JoinNonexistent)
29732979
.Default(TypeOperation::None);
29742980
}
29752981

@@ -3034,6 +3040,25 @@ namespace {
30343040

30353041
return *join;
30363042
}
3043+
3044+
case TypeOperation::JoinNonexistent: {
3045+
auto lhsMeta = CS.getType(lhs)->getAs<MetatypeType>();
3046+
auto rhsMeta = CS.getType(rhs)->getAs<MetatypeType>();
3047+
if (!lhsMeta || !rhsMeta)
3048+
llvm_unreachable("Unexpected argument types for Builtin.type_join_nonexistent!");
3049+
3050+
auto &ctx = lhsMeta->getASTContext();
3051+
3052+
auto join =
3053+
Type::join(lhsMeta->getInstanceType(), rhsMeta->getInstanceType());
3054+
3055+
// Verify that we could not compute a join.
3056+
if (join)
3057+
llvm_unreachable("Unexpected result from join - it should not have been computable!");
3058+
3059+
// The return value is unimportant.
3060+
return MetatypeType::get(ctx.TheAnyType)->getCanonicalType();
3061+
}
30373062
}
30383063
}
30393064
};

lib/Sema/MiscDiagnostics.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
210210
}
211211

212212
// Verify noescape parameter uses.
213-
checkNoEscapeParameterUse(DRE, nullptr, OperandKind::None);
213+
checkNoEscapeParameterUse(DRE, Parent.getAsExpr(), OperandKind::None);
214214

215215
// Verify warn_unqualified_access uses.
216216
checkUnqualifiedAccessUse(DRE);
@@ -703,7 +703,8 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
703703
// The only valid use of the noescape parameter is an immediate call,
704704
// either as the callee or as an argument (in which case, the typechecker
705705
// validates that the noescape bit didn't get stripped off), or as
706-
// a special case, in the binding of a withoutActuallyEscaping block.
706+
// a special case, e.g. in the binding of a withoutActuallyEscaping block
707+
// or the argument of a type(of: ...).
707708
if (parent) {
708709
if (auto apply = dyn_cast<ApplyExpr>(parent)) {
709710
if (isa<ParamDecl>(DRE->getDecl()) && useKind == OperandKind::Callee)
@@ -714,6 +715,8 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
714715
return;
715716
} else if (isa<MakeTemporarilyEscapableExpr>(parent)) {
716717
return;
718+
} else if (isa<DynamicTypeExpr>(parent)) {
719+
return;
717720
}
718721
}
719722

test/Sema/type_join.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import Swift
55
class C {}
66
class D : C {}
77

8-
public func expectEqualType<T>(_: T.Type, _: T.Type) {}
8+
func expectEqualType<T>(_: T.Type, _: T.Type) {}
9+
func commonSupertype<T>(_: T, _: T) -> T {}
910

1011
expectEqualType(Builtin.type_join(Int.self, Int.self), Int.self)
1112
expectEqualType(Builtin.type_join_meta(D.self, C.self), C.self)
@@ -33,6 +34,36 @@ expectEqualType(Builtin.type_join(D?.self, Any.self), Any?.self)
3334
expectEqualType(Builtin.type_join(Any?.self, Any.self), Any?.self)
3435
expectEqualType(Builtin.type_join(Any.self, Any?.self), Any?.self)
3536

37+
func joinFunctions(
38+
_ escaping: @escaping () -> (),
39+
_ nonescaping: () -> ()
40+
) {
41+
_ = commonSupertype(escaping, escaping)
42+
_ = commonSupertype(nonescaping, escaping)
43+
// expected-error@-1 {{converting non-escaping value to 'T' may allow it to escape}}
44+
_ = commonSupertype(escaping, nonescaping)
45+
// expected-error@-1 {{converting non-escaping value to 'T' may allow it to escape}}
46+
let x: Int = 1
47+
// FIXME: We emit these diagnostics here because we refuse to allow
48+
// Any to be inferred for the generic type. That's pretty
49+
// arbitrary.
50+
_ = commonSupertype(escaping, x)
51+
// expected-error@-1 {{cannot convert value of type 'Int' to expected argument type '() -> ()'}}
52+
_ = commonSupertype(x, escaping)
53+
// expected-error@-1 {{cannot convert value of type '() -> ()' to expected argument type 'Int'}}
54+
55+
let a: Any = 1
56+
_ = commonSupertype(nonescaping, a)
57+
// expected-error@-1 {{converting non-escaping value to 'Any' may allow it to escape}}
58+
_ = commonSupertype(a, nonescaping)
59+
// expected-error@-1 {{converting non-escaping value to 'Any' may allow it to escape}}
60+
_ = commonSupertype(escaping, a)
61+
_ = commonSupertype(a, escaping)
62+
63+
expectEqualType(Builtin.type_join(((C) -> C).self, ((C) -> D).self),
64+
((C) -> C).self)
65+
}
66+
3667
func rdar37241221(_ a: C?, _ b: D?) {
3768
let c: C? = C()
3869
let array_c_opt = [c]

0 commit comments

Comments
 (0)