Skip to content

SIL: Round-trip DynamicSelfType properly #4126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ TYPE_ATTR(escaping)
// SIL-specific attributes
TYPE_ATTR(block_storage)
TYPE_ATTR(box)
TYPE_ATTR(dynamic_self)
TYPE_ATTR(sil_unowned)
TYPE_ATTR(sil_unmanaged)
TYPE_ATTR(sil_weak)
Expand Down
14 changes: 13 additions & 1 deletion include/swift/Subsystems.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,19 @@ namespace swift {
///
/// \returns false on success, true on error.
bool performTypeLocChecking(ASTContext &Ctx, TypeLoc &T,
bool isSILType, DeclContext *DC,
DeclContext *DC,
bool ProduceDiagnostics = true);

/// \brief Recursively validate the specified type.
///
/// This is used when dealing with partial source files (e.g. SIL parsing,
/// code completion).
///
/// \returns false on success, true on error.
bool performTypeLocChecking(ASTContext &Ctx, TypeLoc &T,
bool isSILMode,
bool isSILType,
DeclContext *DC,
bool ProduceDiagnostics = true);

/// Expose TypeChecker's handling of GenericParamList to SIL parsing.
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3736,6 +3736,12 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
}

void visitDynamicSelfType(DynamicSelfType *T) {
if (Options.PrintInSILBody) {
Printer << "@dynamic_self ";
visit(T->getSelfType());
return;
}

Printer.printTypeRef(T, T->getASTContext().Id_Self);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
/// \returns true on success, false on failure.
bool typecheckParsedType() {
assert(ParsedTypeLoc.getTypeRepr() && "should have a TypeRepr");
return !performTypeLocChecking(P.Context, ParsedTypeLoc, /*SIL*/ false,
return !performTypeLocChecking(P.Context, ParsedTypeLoc,
CurDeclContext, false);
}

Expand Down
22 changes: 13 additions & 9 deletions lib/Parse/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ namespace {
llvm::function_ref<void(Type)> ParsedTypeCallback;


bool performTypeLocChecking(TypeLoc &T, bool IsSIL = true);
bool performTypeLocChecking(TypeLoc &T, bool IsSILType = true);
bool parseSpecConformanceSubstitutions(
SmallVectorImpl<ParsedSubstitution> &parsed);
ProtocolConformance *parseProtocolConformanceHelper(ProtocolDecl *&proto,
Expand Down Expand Up @@ -770,11 +770,13 @@ static bool parseDeclSILOptional(bool *isTransparent, bool *isFragile,
return false;
}

bool SILParser::performTypeLocChecking(TypeLoc &T, bool IsSIL) {
bool SILParser::performTypeLocChecking(TypeLoc &T, bool IsSILType) {
// Do some type checking / name binding for the parsed type.
assert(P.SF.ASTStage == SourceFile::Parsing &&
"Unexpected stage during parsing!");
return swift::performTypeLocChecking(P.Context, T, /*SIL*/ IsSIL, &P.SF);
return swift::performTypeLocChecking(P.Context, T,
/*isSILMode=*/true,
IsSILType, &P.SF);
}

/// Find the top-level ValueDecl or Module given a name.
Expand Down Expand Up @@ -814,7 +816,7 @@ bool SILParser::parseASTType(CanType &result) {
ParserResult<TypeRepr> parsedType = P.parseType();
if (parsedType.isNull()) return true;
TypeLoc loc = parsedType.get();
if (performTypeLocChecking(loc, false))
if (performTypeLocChecking(loc, /*isSILType=*/ false))
return true;
result = loc.getType()->getCanonicalType();
// Invoke the callback on the parsed type.
Expand Down Expand Up @@ -1371,7 +1373,7 @@ bool SILParser::parseApplySubstitutions(
if (TyR.isNull())
return true;
TypeLoc Ty = TyR.get();
if (performTypeLocChecking(Ty, false))
if (performTypeLocChecking(Ty, /*isSILType=*/ false))
return true;
parsed.push_back({Loc, Ty.getType()});
} while (P.consumeIf(tok::comma));
Expand Down Expand Up @@ -2875,7 +2877,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
}
}

if (performTypeLocChecking(Ty, false))
if (performTypeLocChecking(Ty, /*isSILType=*/ false))
return true;

if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
Expand Down Expand Up @@ -4272,7 +4274,7 @@ bool SILParser::parseSpecConformanceSubstitutions(
if (TyR.isNull())
return true;
TypeLoc Ty = TyR.get();
if (performTypeLocChecking(Ty, false))
if (performTypeLocChecking(Ty, /*isSILType=*/ false))
return true;
parsed.push_back({Loc, Ty.getType()});
} while (P.consumeIf(tok::comma));
Expand Down Expand Up @@ -4326,7 +4328,7 @@ ProtocolConformance *SILParser::parseProtocolConformanceHelper(
if (TyR.isNull())
return nullptr;
TypeLoc Ty = TyR.get();
if (performTypeLocChecking(Ty, false))
if (performTypeLocChecking(Ty, /*isSILType=*/ false))
return nullptr;
auto ConformingTy = Ty.getType();

Expand Down Expand Up @@ -4520,7 +4522,9 @@ bool Parser::parseSILWitnessTable() {
if (TyR.isNull())
return true;
TypeLoc Ty = TyR.get();
if (swift::performTypeLocChecking(Context, Ty, false, &SF))
if (swift::performTypeLocChecking(Context, Ty,
/*isSILMode=*/ false,
/*isSILType=*/ false, &SF))
return true;

witnessEntries.push_back(SILWitnessTable::AssociatedTypeWitness{
Expand Down
3 changes: 1 addition & 2 deletions lib/RemoteAST/RemoteAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,7 @@ class RemoteASTTypeBuilder {
DeclContext *dc = getNotionalDC();

TypeLoc loc(repr);
if (performTypeLocChecking(Ctx, loc, /*SILType*/ false, dc,
/*diagnose*/ false))
if (performTypeLocChecking(Ctx, loc, dc, /*diagnose*/ false))
return Type();

return loc.getType();
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ class SILPrinter : public SILVisitor<SILPrinter> {
PrintState{{PrintCtx.OS()}, PrintOptions::printSIL()},
LastBufferID(0) {
PrintState.ASTOptions.AlternativeTypeNames = AlternativeTypeNames;
PrintState.ASTOptions.PrintForSIL = true;
}

ID getID(const SILBasicBlock *B);
Expand Down
22 changes: 21 additions & 1 deletion lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1724,6 +1724,20 @@ Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) {
llvm_unreachable("all cases should be handled");
}

static Type rebuildWithDynamicSelf(ASTContext &Context, Type ty) {
OptionalTypeKind OTK;
if (auto metatypeTy = ty->getAs<MetatypeType>()) {
return MetatypeType::get(
rebuildWithDynamicSelf(Context, metatypeTy->getInstanceType()),
metatypeTy->getRepresentation());
} else if (auto optionalTy = ty->getAnyOptionalObjectType(OTK)) {
return OptionalType::get(
OTK, rebuildWithDynamicSelf(Context, optionalTy));
} else {
return DynamicSelfType::get(ty, Context);
}
}

Type TypeResolver::resolveAttributedType(AttributedTypeRepr *repr,
TypeResolutionOptions options) {
// Copy the attributes, since we're about to start hacking on them.
Expand Down Expand Up @@ -2018,7 +2032,13 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
ty = SILBoxType::get(ty->getCanonicalType());
attrs.clearAttribute(TAK_box);
}


// In SIL *only*, allow @dynamic_self to specify a dynamic Self type.
if ((options & TR_SILMode) && attrs.has(TAK_dynamic_self)) {
ty = rebuildWithDynamicSelf(TC.Context, ty);
attrs.clearAttribute(TAK_dynamic_self);
}

for (unsigned i = 0; i != TypeAttrKind::TAK_Count; ++i)
if (attrs.has((TypeAttrKind)i))
TC.diagnose(attrs.getLoc((TypeAttrKind)i),
Expand Down
15 changes: 14 additions & 1 deletion lib/Sema/TypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,12 +674,25 @@ void swift::performWholeModuleTypeChecking(SourceFile &SF) {
}

bool swift::performTypeLocChecking(ASTContext &Ctx, TypeLoc &T,
bool isSILType, DeclContext *DC,
DeclContext *DC,
bool ProduceDiagnostics) {
return performTypeLocChecking(Ctx, T,
/*isSILMode=*/false,
/*isSILType=*/false,
DC, ProduceDiagnostics);
}

bool swift::performTypeLocChecking(ASTContext &Ctx, TypeLoc &T,
bool isSILMode,
bool isSILType,
DeclContext *DC,
bool ProduceDiagnostics) {
TypeResolutionOptions options;

// Fine to have unbound generic types.
options |= TR_AllowUnboundGenerics;
if (isSILMode)
options |= TR_SILMode;
if (isSILType)
options |= TR_SILType;

Expand Down
8 changes: 6 additions & 2 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,16 @@ enum TypeResolutionFlags : unsigned {
/// Whether we are validating the type for SIL.
TR_SILType = 0x10,

/// Whether we are parsing a SIL file. Not the same as TR_SILType,
/// because the latter is not set if we're parsing an AST type.
TR_SILMode = 0x20,

/// Whether we are in the input type of a function, or under one level of
/// tuple type. This is not set for multi-level tuple arguments.
TR_FunctionInput = 0x20,
TR_FunctionInput = 0x40,

/// Whether this is the immediate input type to a function type,
TR_ImmediateFunctionInput = 0x40,
TR_ImmediateFunctionInput = 0x80,

/// Whether we are in the result type of a function body that is
/// known to produce dynamic Self.
Expand Down
25 changes: 25 additions & 0 deletions test/SIL/Parser/self.sil
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RUN: %target-swift-frontend %s -parse-stdlib -module-name Swift -emit-silgen | FileCheck %s

enum Optional<T> {
case none
case some(T)
}

enum ImplicitlyUnwrappedOptional<T> {
case none
case some(T)
}

class SelfTest {}

sil_vtable SelfTest {}

sil @test_stuff : $@convention(thin) (@owned SelfTest) -> () {
bb0(%0 : $SelfTest):
// CHECK: metatype $@thick @dynamic_self SelfTest
%2 = metatype $@thick @dynamic_self SelfTest.Type
// CHECK: metatype $@thick Optional<@dynamic_self SelfTest>.Type
%5 = metatype $@thick @dynamic_self SelfTest?.Type
%7 = tuple ()
return %7 : $()
}
10 changes: 5 additions & 5 deletions test/SILGen/dynamic_self.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func testDynamicSelfDispatch(y: Y) {
// CHECK: bb0([[Y:%[0-9]+]] : $Y):
// CHECK: strong_retain [[Y]]
// CHECK: [[Y_AS_X:%[0-9]+]] = upcast [[Y]] : $Y to $X
// CHECK: [[X_F:%[0-9]+]] = class_method [[Y_AS_X]] : $X, #X.f!1 : (X) -> () -> Self , $@convention(method) (@guaranteed X) -> @owned X
// CHECK: [[X_F:%[0-9]+]] = class_method [[Y_AS_X]] : $X, #X.f!1 : (X) -> () -> @dynamic_self X , $@convention(method) (@guaranteed X) -> @owned X
// CHECK: [[X_RESULT:%[0-9]+]] = apply [[X_F]]([[Y_AS_X]]) : $@convention(method) (@guaranteed X) -> @owned X
// CHECK: strong_release [[Y_AS_X]]
// CHECK: [[Y_RESULT:%[0-9]+]] = unchecked_ref_cast [[X_RESULT]] : $X to $Y
Expand All @@ -50,7 +50,7 @@ func testDynamicSelfDispatchGeneric(gy: GY<Int>) {
// CHECK: bb0([[GY:%[0-9]+]] : $GY<Int>):
// CHECK: strong_retain [[GY]]
// CHECK: [[GY_AS_GX:%[0-9]+]] = upcast [[GY]] : $GY<Int> to $GX<Array<Int>>
// CHECK: [[GX_F:%[0-9]+]] = class_method [[GY_AS_GX]] : $GX<Array<Int>>, #GX.f!1 : <T> (GX<T>) -> () -> Self , $@convention(method) <τ_0_0> (@guaranteed GX<τ_0_0>) -> @owned GX<τ_0_0>
// CHECK: [[GX_F:%[0-9]+]] = class_method [[GY_AS_GX]] : $GX<Array<Int>>, #GX.f!1 : <T> (GX<T>) -> () -> @dynamic_self GX<T> , $@convention(method) <τ_0_0> (@guaranteed GX<τ_0_0>) -> @owned GX<τ_0_0>
// CHECK: [[GX_RESULT:%[0-9]+]] = apply [[GX_F]]<[Int]>([[GY_AS_GX]]) : $@convention(method) <τ_0_0> (@guaranteed GX<τ_0_0>) -> @owned GX<τ_0_0>
// CHECK: strong_release [[GY_AS_GX]]
// CHECK: [[GY_RESULT:%[0-9]+]] = unchecked_ref_cast [[GX_RESULT]] : $GX<Array<Int>> to $GY<Int>
Expand Down Expand Up @@ -145,7 +145,7 @@ func testOptionalResult(v : OptionalResultInheritor) {
v.foo()?.bar()
}
// CHECK-LABEL: sil hidden @_TF12dynamic_self18testOptionalResult{{.*}} : $@convention(thin) (@owned OptionalResultInheritor) -> ()
// CHECK: [[T0:%.*]] = class_method [[V:%.*]] : $OptionalResult, #OptionalResult.foo!1 : (OptionalResult) -> () -> Self? , $@convention(method) (@guaranteed OptionalResult) -> @owned Optional<OptionalResult>
// CHECK: [[T0:%.*]] = class_method [[V:%.*]] : $OptionalResult, #OptionalResult.foo!1 : (OptionalResult) -> () -> @dynamic_self OptionalResult? , $@convention(method) (@guaranteed OptionalResult) -> @owned Optional<OptionalResult>
// CHECK-NEXT: [[RES:%.*]] = apply [[T0]]([[V]])
// CHECK: select_enum [[RES]]
// CHECK: [[T1:%.*]] = unchecked_enum_data [[RES]]
Expand Down Expand Up @@ -183,8 +183,8 @@ class Z {
// CHECK: [[WEAK_SELF:%.*]] = alloc_box $@sil_weak Optional<Z>
// CHECK: [[FN:%.*]] = function_ref @_TFFC12dynamic_self1Z23testDynamicSelfCapturesFT1xSi_DS0_U1_FT_T_ : $@convention(thin) (@owned @box @sil_weak Optional<Z>, @thick Z.Type) -> ()
// CHECK: strong_retain [[WEAK_SELF]] : $@box @sil_weak Optional<Z>
// CHECK-NEXT: [[DYNAMIC_SELF:%.*]] = metatype $@thick Self.Type
// CHECK-NEXT: [[STATIC_SELF:%.*]] = upcast [[DYNAMIC_SELF]] : $@thick Self.Type to $@thick Z.Type
// CHECK-NEXT: [[DYNAMIC_SELF:%.*]] = metatype $@thick @dynamic_self Z.Type
// CHECK-NEXT: [[STATIC_SELF:%.*]] = upcast [[DYNAMIC_SELF]] : $@thick @dynamic_self Z.Type to $@thick Z.Type
// CHECK: partial_apply [[FN]]([[WEAK_SELF]], [[STATIC_SELF]]) : $@convention(thin) (@owned @box @sil_weak Optional<Z>, @thick Z.Type) -> ()
let fn3 = {
[weak self] in
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/existential_erasure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class EraseDynamicSelf {

// CHECK-LABEL: sil hidden @_TZFC19existential_erasure16EraseDynamicSelf7factoryfT_DS0_ : $@convention(method) (@thick EraseDynamicSelf.Type) -> @owned EraseDynamicSelf
// CHECK: [[ANY:%.*]] = alloc_stack $Any
// CHECK: init_existential_addr [[ANY]] : $*Any, $Self
// CHECK: init_existential_addr [[ANY]] : $*Any, $@dynamic_self EraseDynamicSelf
//
class func factory() -> Self {
let instance = self.init()
Expand Down
2 changes: 1 addition & 1 deletion test/SILOptimizer/functionsigopts_self.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extension C {
// CHECK-LABEL: sil hidden @_TTSf4d_n___TZFC20functionsigopts_self1C7factory{{.*}} : $@convention(method) (@thick C.Type) -> @owned C
// CHECK: bb0(%0 : $@thick C.Type):
// CHECK: function_ref functionsigopts_self.gen <A> () -> A
// CHECK: apply %{{[0-9]+}}<Self>
// CHECK: apply %{{[0-9]+}}<@dynamic_self C>

// Call the function so the specialization is not dead.
var x = C()
Expand Down
2 changes: 1 addition & 1 deletion test/SILOptimizer/specialize_self.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func cast<T,R>(_ x: T) -> R? {
// CHECK-LABEL: static specialize_self.Base.returnIfSelf (Swift.AnyObject) -> Swift.Optional<Self>
// CHECK-NEXT: sil hidden @_TZFC15specialize_self4Base12returnIfSelf{{.*}} : $@convention(method) (@owned AnyObject, @thick Base.Type) -> @owned Optional<Base>
// CHECK: [[CAST:%[0-9]+]] = function_ref @_TF15specialize_self4cast
// CHECK: apply [[CAST]]<AnyObject, Self>
// CHECK: apply [[CAST]]<AnyObject, @dynamic_self Base>
class Base {
class func returnIfSelf(_ x: AnyObject) -> Self? {
return cast(x)
Expand Down