diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h index 37c4cb3eff233..30b6722f40e3d 100644 --- a/include/swift/SILOptimizer/Utils/Local.h +++ b/include/swift/SILOptimizer/Utils/Local.h @@ -137,21 +137,17 @@ ProjectBoxInst *getOrCreateProjectBox(AllocBoxInst *ABI, unsigned Index); /// if possible. void replaceDeadApply(ApplySite Old, ValueBase *New); -/// \brief Return true if the substitution map contains a -/// substitution that is an unbound generic type. -bool hasUnboundGenericTypes(const TypeSubstitutionMap &SubsMap); +/// \brief Return true if the substitution map contains replacement types +/// that are dependent on the type parameters of the caller. +bool hasTypeParameterTypes(SubstitutionMap &SubsMap); -/// Return true if the substitution list contains a substitution -/// that is an unbound generic. -bool hasUnboundGenericTypes(ArrayRef Subs); +/// \brief Return true if the substitution list contains replacement types +/// that are dependent on the type parameters of the caller. +bool hasArchetypes(ArrayRef Subs); /// \brief Return true if the substitution map contains a /// substitution that refers to the dynamic Self type. -bool hasDynamicSelfTypes(const TypeSubstitutionMap &SubsMap); - -/// \brief Return true if the substitution list contains a -/// substitution that refers to the dynamic Self type. -bool hasDynamicSelfTypes(ArrayRef Subs); +bool hasDynamicSelfTypes(const SubstitutionMap &SubsMap); /// \brief Return true if any call inside the given function may bind dynamic /// 'Self' to a generic argument of the callee. diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 4b12a32718e7b..7a9a901f4d526 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -1249,9 +1249,9 @@ struct ASTNodeBase {}; Out << "\n"; abort(); } - CanType InputExprTy = E->getArg()->getType()->getCanonicalType(); - CanType ResultExprTy = E->getType()->getCanonicalType(); - if (ResultExprTy != FT->getResult()->getCanonicalType()) { + Type InputExprTy = E->getArg()->getType(); + Type ResultExprTy = E->getType(); + if (!ResultExprTy->isEqual(FT->getResult())) { Out << "result of ApplyExpr does not match result type of callee:"; E->getType().print(Out); Out << " vs. "; @@ -1259,7 +1259,7 @@ struct ASTNodeBase {}; Out << "\n"; abort(); } - if (InputExprTy != FT->getInput()->getCanonicalType()) { + if (!InputExprTy->isEqual(FT->getInput())) { TupleType *TT = FT->getInput()->getAs(); if (isa(E)) { Type InputExprObjectTy; @@ -1274,8 +1274,7 @@ struct ASTNodeBase {}; checkSameOrSubType(InputExprObjectTy, FunctionInputObjectTy, "object argument and 'self' parameter"); } else if (!TT || TT->getNumElements() != 1 || - TT->getElement(0).getType()->getCanonicalType() - != InputExprTy) { + !TT->getElement(0).getType()->isEqual(InputExprTy)) { Out << "Argument type does not match parameter type in ApplyExpr:" "\nArgument type: "; E->getArg()->getType().print(Out); @@ -1892,8 +1891,7 @@ struct ASTNodeBase {}; return; } - if (type->getCanonicalType() != - conformance.getConcrete()->getType()->getCanonicalType()) { + if (!type->isEqual(conformance.getConcrete()->getType())) { Out << "conforming type does not match conformance\n"; Out << "conforming type:\n"; type.dump(Out, 2); @@ -2518,7 +2516,7 @@ struct ASTNodeBase {}; } void checkSameType(Type T0, Type T1, const char *what) { - if (T0->getCanonicalType() == T1->getCanonicalType()) + if (T0->isEqual(T1)) return; Out << "different types for " << what << ": "; @@ -2568,7 +2566,7 @@ struct ASTNodeBase {}; } void checkSameOrSubType(Type T0, Type T1, const char *what) { - if (T0->getCanonicalType() == T1->getCanonicalType()) + if (T0->isEqual(T1)) return; // Protocol subtyping. diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 3c69c9757444c..e8c2e71c026bf 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -188,7 +188,7 @@ class AvailabilityInferenceTypeWalker : public TypeWalker { AvailabilityInferenceTypeWalker(ASTContext &AC) : AC(AC) {} Action walkToTypePre(Type ty) override { - if (auto *nominalDecl = ty->getCanonicalType()->getAnyNominal()) { + if (auto *nominalDecl = ty->getAnyNominal()) { AvailabilityInfo.intersectWith( AvailabilityInference::availableRange(nominalDecl, AC)); } diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index a896a4464ca32..b114e69a26fee 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -391,7 +391,7 @@ static void formatDiagnosticArgument(StringRef Modifier, showAKA = false; // Don't show generic type parameters. - if (showAKA && type->getCanonicalType()->hasTypeParameter()) + if (showAKA && type->hasTypeParameter()) showAKA = false; if (showAKA) diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 22549e1188493..96ea56d4de7a8 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -466,7 +466,7 @@ Type GenericSignature::getRepresentative(Type type, ModuleDecl &mod) { if (rep->isConcreteType()) return rep->getConcreteType(); if (pa == rep) { assert(rep->getDependentType(getGenericParams(), /*allowUnresolved*/ false) - ->getCanonicalType() == type->getCanonicalType()); + ->isEqual(type)); return type; } return rep->getDependentType(getGenericParams(), /*allowUnresolved*/ false); diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index aa02cbf5f7c69..5d85846a40cf1 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -414,8 +414,7 @@ SpecializedProtocolConformance::getTypeWitnessSubstAndDecl( assert((conforms || specializedType->isTypeVariableOrMember() || specializedType->isTypeParameter() || - specializedType->hasError() || - specializedType->getCanonicalType()->hasError()) && + specializedType->hasError()) && "Improperly checked substitution"); conformances.push_back(conforms ? *conforms : ProtocolConformanceRef(proto)); diff --git a/lib/AST/Substitution.cpp b/lib/AST/Substitution.cpp index affbd4b014535..9e0844c3fed50 100644 --- a/lib/AST/Substitution.cpp +++ b/lib/AST/Substitution.cpp @@ -29,7 +29,7 @@ bool Substitution::operator==(const Substitution &other) const { // The archetypes may be missing, but we can compare them directly // because archetypes are always canonical. return - Replacement->getCanonicalType() == other.Replacement->getCanonicalType() && + Replacement->isEqual(other.Replacement) && Conformance.equals(other.Conformance); } diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 1ca3dfe99d09f..af5239be3868e 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -3708,7 +3708,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // We can only say .foo where foo is a static member of the contextual // type and has the same type (or if the member is a function, then the // same result type) as the contextual type. - auto contextCanT = T->getCanonicalType(); FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind reason) { if (!VD->hasInterfaceType()) { TypeResolver->resolveDeclSignature(VD); @@ -3716,10 +3715,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { return false; } - auto T = VD->getInterfaceType(); - while (auto FT = T->getAs()) - T = FT->getResult(); - return T->getCanonicalType() == contextCanT; + auto declTy = VD->getInterfaceType(); + while (auto FT = declTy->getAs()) + declTy = FT->getResult(); + return declTy->isEqual(T); }); auto baseType = MetatypeType::get(T); diff --git a/lib/IDE/TypeReconstruction.cpp b/lib/IDE/TypeReconstruction.cpp index e85bdfb157f07..eb5aaf5bf6cbd 100644 --- a/lib/IDE/TypeReconstruction.cpp +++ b/lib/IDE/TypeReconstruction.cpp @@ -945,10 +945,10 @@ static void VisitNodeConstructor( const AnyFunctionType *type_func = type_result._types.front()->getAs(); - if (identifier_func->getResult()->getCanonicalType() == - type_func->getResult()->getCanonicalType() && - identifier_func->getInput()->getCanonicalType() == - type_func->getInput()->getCanonicalType()) { + if (identifier_func->getResult()->isEqual( + type_func->getResult()) && + identifier_func->getInput()->isEqual( + type_func->getInput())) { result._module = kind_type_result._module; result._decls.push_back(kind_type_result._decls[i]); result._types.push_back( @@ -1481,8 +1481,8 @@ static void VisitNodeSetterGetter( const AnyFunctionType *type_func = type_result._types.front()->getAs(); - CanType type_result_type = type_func->getResult()->getCanonicalType(); - CanType type_input_type = type_func->getInput()->getCanonicalType(); + Type type_result_type = type_func->getResult(); + Type type_input_type = type_func->getInput(); FuncDecl *identifier_func = nullptr; @@ -1520,14 +1520,12 @@ static void VisitNodeSetterGetter( const AnyFunctionType *identifier_uncurried_result = identifier_func_type->getResult()->getAs(); if (identifier_uncurried_result) { - CanType identifier_result_type = - identifier_uncurried_result->getResult() - ->getCanonicalType(); - CanType identifier_input_type = - identifier_uncurried_result->getInput() - ->getCanonicalType(); - if (identifier_result_type == type_result_type && - identifier_input_type == type_input_type) { + Type identifier_result_type = + identifier_uncurried_result->getResult(); + Type identifier_input_type = + identifier_uncurried_result->getInput(); + if (identifier_result_type->isEqual(type_result_type) && + identifier_input_type->isEqual(type_input_type)) { break; } } diff --git a/lib/SILOptimizer/IPO/UsePrespecialized.cpp b/lib/SILOptimizer/IPO/UsePrespecialized.cpp index f12a93302ac49..6850b138c08f5 100644 --- a/lib/SILOptimizer/IPO/UsePrespecialized.cpp +++ b/lib/SILOptimizer/IPO/UsePrespecialized.cpp @@ -94,14 +94,9 @@ bool UsePrespecialized::replaceByPrespecialized(SILFunction &F) { if (!SpecType) continue; - // Bail if any generic types parameters of the concrete type - // are unbound. - if (SpecType->hasArchetype()) - continue; - - // Bail if any generic types parameters of the concrete type - // are unbound. - if (hasUnboundGenericTypes(Subs)) + // Bail any callee generic type parameters are dependent on the generic + // parameters of the caller. + if (SpecType->hasArchetype() || hasArchetypes(Subs)) continue; // Create a name of the specialization. diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp index 5dc087a0f7b9a..55518d855bb9d 100644 --- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp +++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp @@ -390,7 +390,7 @@ static Optional shouldInlineGeneric(FullApplySite AI) { // If all substitutions are concrete, then there is no need to perform the // generic inlining. Let the generic specializer create a specialized // function and then decide if it is beneficial to inline it. - if (!hasUnboundGenericTypes(AI.getSubstitutions())) + if (!hasArchetypes(AI.getSubstitutions())) return false; SILFunction *Callee = AI.getReferencedFunction(); diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 31c4ad3040e84..8444c62e45660 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -63,7 +63,7 @@ ReabstractionInfo::ReabstractionInfo(SILFunction *OrigF, ->getSubstitutionMap(ParamSubs); // We do not support partial specialization. - if (hasUnboundGenericTypes(InterfaceSubs.getMap())) { + if (hasTypeParameterTypes(InterfaceSubs)) { DEBUG(llvm::dbgs() << " Cannot specialize with unbound interface substitutions.\n"); DEBUG(for (auto Sub : ParamSubs) { @@ -71,7 +71,7 @@ ReabstractionInfo::ReabstractionInfo(SILFunction *OrigF, }); return; } - if (hasDynamicSelfTypes(InterfaceSubs.getMap())) { + if (hasDynamicSelfTypes(InterfaceSubs)) { DEBUG(llvm::dbgs() << " Cannot specialize with dynamic self.\n"); return; } diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp index 9e561d9ffd427..9023f32ecdd9d 100644 --- a/lib/SILOptimizer/Utils/Local.cpp +++ b/lib/SILOptimizer/Utils/Local.cpp @@ -322,36 +322,27 @@ void swift::replaceDeadApply(ApplySite Old, ValueBase *New) { recursivelyDeleteTriviallyDeadInstructions(OldApply, true); } -bool swift::hasUnboundGenericTypes(const TypeSubstitutionMap &SubsMap) { +bool swift::hasTypeParameterTypes(SubstitutionMap &SubsMap) { // Check whether any of the substitutions are dependent. - for (auto &entry : SubsMap) - if (entry.second->getCanonicalType()->hasArchetype()) + for (auto &entry : SubsMap.getMap()) + if (entry.second->hasArchetype()) return true; return false; } -bool swift::hasUnboundGenericTypes(ArrayRef Subs) { +bool swift::hasArchetypes(ArrayRef Subs) { // Check whether any of the substitutions are dependent. for (auto &sub : Subs) - if (sub.getReplacement()->getCanonicalType()->hasArchetype()) + if (sub.getReplacement()->hasArchetype()) return true; return false; } -bool swift::hasDynamicSelfTypes(const TypeSubstitutionMap &SubsMap) { +bool swift::hasDynamicSelfTypes(const SubstitutionMap &SubsMap) { // Check whether any of the substitutions are refer to dynamic self. - for (auto &entry : SubsMap) - if (entry.second->getCanonicalType()->hasDynamicSelfType()) - return true; - - return false; -} - -bool swift::hasDynamicSelfTypes(ArrayRef Subs) { - // Check whether any of the substitutions are refer to dynamic self. - for (auto &sub : Subs) - if (sub.getReplacement()->getCanonicalType()->hasDynamicSelfType()) + for (auto &entry : SubsMap.getMap()) + if (entry.second->hasDynamicSelfType()) return true; return false; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 01580b86c5ed2..16e715dc2aaed 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -213,8 +213,8 @@ static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member, #endif // Ctor or dtor are for immediate class, not a derived class. - if (AFD->getParent()->getDeclaredTypeOfContext()->getCanonicalType() != - member->getDeclContext()->getDeclaredTypeOfContext()->getCanonicalType()) + if (!AFD->getParent()->getDeclaredInterfaceType()->isEqual( + member->getDeclContext()->getDeclaredInterfaceType())) return false; return true; @@ -247,8 +247,8 @@ getImplicitMemberReferenceAccessSemantics(Expr *base, VarDecl *member, isa(AFD_DC) && // Ctor is for immediate class, not a derived class. - AFD_DC->getParent()->getDeclaredTypeOfContext()->getCanonicalType() == - member->getDeclContext()->getDeclaredTypeOfContext()->getCanonicalType() && + AFD_DC->getParent()->getDeclaredInterfaceType()->isEqual( + member->getDeclContext()->getDeclaredInterfaceType()) && // Is a "self.property" reference. isa(base) && @@ -4704,21 +4704,18 @@ static unsigned getOptionalBindDepth(const BoundGenericType *bgt) { unsigned innerDepth = 0; - if (auto wrappedBGT = dyn_cast(tyarg-> - getCanonicalType())) { + if (auto wrappedBGT = tyarg->getAs()) innerDepth = getOptionalBindDepth(wrappedBGT); - } - + return 1 + innerDepth; } return 0; } -static Type getOptionalBaseType(const Type &type) { +static Type getOptionalBaseType(Type type) { - if (auto bgt = dyn_cast(type-> - getCanonicalType())) { + if (auto bgt = type->getAs()) { if (bgt->getDecl()->classifyAsOptionalType()) { return getOptionalBaseType(bgt->getGenericArgs()[0]); } @@ -6102,7 +6099,7 @@ Expr *ExprRewriter::convertLiteral(Expr *literal, return nullptr; // If the argument type is in error, we're done. - if (argType->hasError() || argType->getCanonicalType()->hasError()) + if (argType->hasError()) return nullptr; // Convert the literal to the non-builtin argument type via the diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 3208e9c6d1e61..2235767005ee2 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -2547,8 +2547,8 @@ diagnoseTypeMemberOnInstanceLookup(Type baseObjTy, // If we are in a protocol extension of 'Proto' and we see // 'Proto.static', suggest 'Self.static' if (auto extensionContext = parent->getAsProtocolExtensionContext()) { - if (extensionContext->getDeclaredType()->getCanonicalType() - == metatypeTy->getInstanceType()->getCanonicalType()) { + if (extensionContext->getDeclaredType()->isEqual( + metatypeTy->getInstanceType())) { Diag->fixItReplace(baseRange, "Self"); } } @@ -3562,8 +3562,7 @@ typeCheckArbitrarySubExprIndependently(Expr *subExpr, TCCOptions options) { // in. Reset them to UnresolvedTypes for safe measures. for (auto param : *CE->getParameters()) { auto VD = param; - if (VD->getType()->hasTypeVariable() || VD->getType()->hasError() || - VD->getType()->getCanonicalType()->hasError()) { + if (VD->getType()->hasTypeVariable() || VD->getType()->hasError()) { VD->setType(CS->getASTContext().TheUnresolvedType); VD->setInterfaceType(VD->getType()); } @@ -4962,8 +4961,7 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, CallArgParam &arg = args[0]; auto resTy = candidate.getResultType()->lookThroughAllAnyOptionalTypes(); auto rawTy = isRawRepresentable(resTy, CCI.CS); - if (rawTy && arg.Ty && - resTy->getCanonicalType() == arg.Ty->getCanonicalType()) { + if (rawTy && arg.Ty && resTy->isEqual(arg.Ty)) { auto getInnerExpr = [](Expr *E) -> Expr* { ParenExpr *parenE = dyn_cast(E); if (!parenE) @@ -6408,8 +6406,7 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { // // Handle this by rewriting the arguments to UnresolvedType(). for (auto VD : *CE->getParameters()) { - if (VD->getType()->hasTypeVariable() || VD->getType()->hasError() || - VD->getType()->getCanonicalType()->hasError()) { + if (VD->getType()->hasTypeVariable() || VD->getType()->hasError()) { VD->setType(CS->getASTContext().TheUnresolvedType); VD->setInterfaceType(VD->getType()); } diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 3202a498e0326..ed6909dc5bd3b 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2855,9 +2855,7 @@ namespace { // If the function type has an error in it, we don't want to solve the // system. - if (closureTy && - (closureTy->hasError() || - closureTy->getCanonicalType()->hasError())) + if (closureTy && closureTy->hasError()) return nullptr; CS.setType(closure, closureTy); diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index a3e84691791be..fcc284b2f5f49 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -776,7 +776,7 @@ static void addTrivialAccessorsToStorage(AbstractStorageDecl *storage, if (isDynamic) setter->getAttrs().add(new (TC.Context) DynamicAttr(IsImplicit)); - // Synthesize and type-check the body of the setter. + // Synthesize the body of the setter. synthesizeTrivialSetter(setter, storage, setterValueParam, TC); } @@ -800,7 +800,7 @@ synthesizeSetterForMutableAddressedStorage(AbstractStorageDecl *storage, assert(storage->getStorageKind() == AbstractStorageDecl::ComputedWithMutableAddress); - // Synthesize and type-check the body of the setter. + // Synthesize the body of the setter. VarDecl *valueParamDecl = getFirstParamDecl(setter); synthesizeTrivialSetter(setter, storage, valueParamDecl, TC); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 34322c5c00075..3992c8f1f8c54 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -954,10 +954,8 @@ void ConstraintSystem::openGeneric( // skip. if (skipProtocolSelfConstraint && protoDecl == outerDC && - (protoDecl->getSelfInterfaceType()->getCanonicalType() == - req.getFirstType()->getCanonicalType())) { + protoDecl->getSelfInterfaceType()->isEqual(req.getFirstType())) break; - } addConstraint(ConstraintKind::ConformsTo, subjectTy, proto, locatorPtr); diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index f725cd31cee0a..0cba4034e5007 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -452,7 +452,7 @@ class Instrumenter : InstrumenterBase { } } if (!Handled && - AE->getType()->getCanonicalType() == Context.TheEmptyTupleType) { + AE->getType()->isEqual(Context.TheEmptyTupleType)) { if (auto *DSCE = dyn_cast(AE->getFn())) { Expr *TargetExpr = DSCE->getArg(); Added Target_RE; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 26b659c144673..8d7dabb3ab16c 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1306,7 +1306,9 @@ void AttributeChecker::visitRethrowsAttr(RethrowsAttr *attr) { auto fn = cast(D); for (auto paramList : fn->getParameterLists()) { for (auto param : *paramList) - if (hasThrowingFunctionParameter(param->getType()->lookThroughAllAnyOptionalTypes()->getCanonicalType())) + if (hasThrowingFunctionParameter(param->getType() + ->lookThroughAllAnyOptionalTypes() + ->getCanonicalType())) return; } @@ -1430,7 +1432,7 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { return; } - if (ty->getCanonicalType()->hasArchetype()) { + if (ty->hasArchetype()) { TC.diagnose(attr->getLocation(), diag::cannot_partially_specialize_generic_function); attr->setInvalid(); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 2b40298c513f5..952ed6f2c72c1 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -3517,6 +3517,32 @@ void TypeChecker::validateDecl(OperatorDecl *OD) { } } +static void validateAbstractStorageDecl(AbstractStorageDecl *ASD, + TypeChecker &TC) { + if (ASD->hasAccessorFunctions()) + maybeAddMaterializeForSet(ASD, TC); + + if (ASD->isFinal()) { + makeFinal(TC.Context, ASD->getGetter()); + makeFinal(TC.Context, ASD->getSetter()); + makeFinal(TC.Context, ASD->getMaterializeForSetFunc()); + } + + if (auto getter = ASD->getGetter()) + TC.validateDecl(getter); + if (auto setter = ASD->getSetter()) + TC.validateDecl(setter); + if (auto materializeForSet = ASD->getMaterializeForSetFunc()) + TC.validateDecl(materializeForSet); + if (ASD->hasAddressors()) { + if (auto addressor = ASD->getAddressor()) + TC.validateDecl(addressor); + if (auto addressor = ASD->getMutableAddressor()) + TC.validateDecl(addressor); + } + +} + namespace { class DeclChecker : public DeclVisitor { public: @@ -3885,25 +3911,7 @@ class DeclChecker : public DeclVisitor { inferDynamic(TC.Context, SD); } - if (SD->hasAccessorFunctions()) - maybeAddMaterializeForSet(SD, TC); - - // If this subscript is marked final and has a getter or setter, mark the - // getter and setter as final as well. - if (SD->isFinal()) { - makeFinal(TC.Context, SD->getGetter()); - makeFinal(TC.Context, SD->getSetter()); - makeFinal(TC.Context, SD->getMaterializeForSetFunc()); - } - - // Make sure the getter and setter have valid types, since they will be - // used by SILGen for any accesses to this subscript. - if (auto getter = SD->getGetter()) - TC.validateDecl(getter); - if (auto setter = SD->getSetter()) - TC.validateDecl(setter); - if (auto materializeForSet = SD->getMaterializeForSetFunc()) - TC.validateDecl(materializeForSet); + validateAbstractStorageDecl(SD, TC); // If this is a get+mutableAddress property, synthesize the setter body. if (SD->getStorageKind() == SubscriptDecl::ComputedWithMutableAddress && @@ -7113,25 +7121,11 @@ void TypeChecker::validateDecl(ValueDecl *D) { // Synthesize accessors as necessary. maybeAddAccessorsToVariable(VD, *this); - if (VD->hasAccessorFunctions()) - maybeAddMaterializeForSet(VD, *this); - // Make sure the getter and setter have valid types, since they will be // used by SILGen for any accesses to this variable. - if (auto getter = VD->getGetter()) - validateDecl(getter); - if (auto setter = VD->getSetter()) - validateDecl(setter); - if (auto materializeForSet = VD->getMaterializeForSetFunc()) - validateDecl(materializeForSet); - - // If this variable is marked final and has a getter or setter, mark the - // getter and setter as final as well. - if (VD->isFinal()) { - makeFinal(Context, VD->getGetter()); - makeFinal(Context, VD->getSetter()); - makeFinal(Context, VD->getMaterializeForSetFunc()); - } else if (VD->isDynamic()) { + validateAbstractStorageDecl(VD, *this); + + if (VD->isDynamic()) { makeDynamic(Context, VD->getGetter()); makeDynamic(Context, VD->getSetter()); // Skip materializeForSet -- it won't be used with a dynamic property. diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index c8a50718501c3..10d70976f0ea7 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -4317,7 +4317,7 @@ static void diagnoseConformanceFailure(TypeChecker &TC, Type T, ProtocolDecl *Proto, DeclContext *DC, SourceLoc ComplainLoc) { - if (T->hasError() || T->getCanonicalType()->hasError()) + if (T->hasError()) return; // If we're checking conformance of an existential type to a protocol, diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 261ecfd65ed76..1c61894b48e82 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -254,7 +254,7 @@ static void tryDiagnoseUnnecessaryCastOverOptionSet(ASTContext &Ctx, MemberRefExpr *BME = dyn_cast(ME->getBase()); if (!BME) return; - if (BME->getType()->getCanonicalType() != ResultType->getCanonicalType()) + if (!BME->getType()->isEqual(ResultType)) return; Ctx.Diags.diagnose(E->getLoc(), diag::unnecessary_cast_over_optionset, @@ -709,7 +709,7 @@ class StmtChecker : public StmtVisitor { TC.Context.Id_next, {}, diag::iterator_protocol_broken); if (!iteratorNext) return nullptr; // Check that next() produces an Optional value. - if (iteratorNext->getType()->getCanonicalType()->getAnyNominal() + if (iteratorNext->getType()->getAnyNominal() != TC.Context.getOptionalDecl()) { TC.diagnose(S->getForLoc(), diag::iterator_protocol_broken); return nullptr; diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 504a0f0f6f044..017091d8b91b8 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -407,6 +407,87 @@ void TypeChecker::bindExtension(ExtensionDecl *ext) { ::bindExtensionDecl(ext, *this); } +static bool shouldValidateDeclForLayout(NominalTypeDecl *nominal, ValueDecl *VD) { + // For enums, we only need to validate enum elements to know + // the layout. + if (isa(nominal) && + isa(VD)) + return true; + + // For structs, we only need to validate stored properties to + // know the layout. + if (isa(nominal) && + (isa(VD) && + !cast(VD)->isStatic() && + (cast(VD)->hasStorage() || + VD->getAttrs().hasAttribute()))) + return true; + + // For classes, we need to validate properties and functions, + // but skipping nested types is OK. + if (isa(nominal) && + !isa(VD)) + return true; + + // For protocols, skip nested typealiases and nominal types. + if (isa(nominal) && + !isa(VD)) + return true; + + return false; +} + +static void validateDeclForLayout(TypeChecker &TC, NominalTypeDecl *nominal) { + Optional lazyVarsAlreadyHaveImplementation; + + for (auto *D : nominal->getMembers()) { + auto VD = dyn_cast(D); + if (!VD) + continue; + + if (!shouldValidateDeclForLayout(nominal, VD)) + continue; + + TC.validateDecl(VD); + + // The only thing left to do is synthesize storage for lazy variables. + // We only have to do that if it's a type from another file, though. + // In NDEBUG builds, bail out as soon as we can. +#ifdef NDEBUG + if (lazyVarsAlreadyHaveImplementation.hasValue() && + lazyVarsAlreadyHaveImplementation.getValue()) + continue; +#endif + auto *prop = dyn_cast(D); + if (!prop) + continue; + + if (prop->getAttrs().hasAttribute() && !prop->isStatic() + && prop->getGetter()) { + bool hasImplementation = prop->getGetter()->hasBody(); + + if (lazyVarsAlreadyHaveImplementation.hasValue()) { + assert(lazyVarsAlreadyHaveImplementation.getValue() == + hasImplementation && + "only some lazy vars already have implementations"); + } else { + lazyVarsAlreadyHaveImplementation = hasImplementation; + } + + if (!hasImplementation) + TC.completeLazyVarImplementation(prop); + } + } + + // FIXME: We need to add implicit initializers and dtors when a decl is + // touched, because it affects vtable layout. If you're not defining the + // class, you shouldn't have to know what the vtable layout is. + if (auto *CD = dyn_cast(nominal)) { + TC.addImplicitConstructors(CD); + TC.addImplicitDestructor(CD); + } +} + static void typeCheckFunctionsAndExternalDecls(TypeChecker &TC) { unsigned currentFunctionIdx = 0; unsigned currentExternalDef = TC.Context.LastCheckedExternalDefinition; @@ -462,50 +543,7 @@ static void typeCheckFunctionsAndExternalDecls(TypeChecker &TC) { if (nominal->isInvalid() || TC.Context.hadError()) continue; - Optional lazyVarsAlreadyHaveImplementation; - - for (auto *D : nominal->getMembers()) { - auto VD = dyn_cast(D); - if (!VD) - continue; - TC.validateDecl(VD); - - // The only thing left to do is synthesize storage for lazy variables. - // We only have to do that if it's a type from another file, though. - // In NDEBUG builds, bail out as soon as we can. -#ifdef NDEBUG - if (lazyVarsAlreadyHaveImplementation.hasValue() && - lazyVarsAlreadyHaveImplementation.getValue()) - continue; -#endif - auto *prop = dyn_cast(D); - if (!prop) - continue; - - if (prop->getAttrs().hasAttribute() && !prop->isStatic() - && prop->getGetter()) { - bool hasImplementation = prop->getGetter()->hasBody(); - - if (lazyVarsAlreadyHaveImplementation.hasValue()) { - assert(lazyVarsAlreadyHaveImplementation.getValue() == - hasImplementation && - "only some lazy vars already have implementations"); - } else { - lazyVarsAlreadyHaveImplementation = hasImplementation; - } - - if (!hasImplementation) - TC.completeLazyVarImplementation(prop); - } - } - - // FIXME: We need to add implicit initializers and dtors when a decl is - // touched, because it affects vtable layout. If you're not defining the - // class, you shouldn't have to know what the vtable layout is. - if (auto *CD = dyn_cast(nominal)) { - TC.addImplicitConstructors(CD); - TC.addImplicitDestructor(CD); - } + validateDeclForLayout(TC, nominal); } // Complete any conformances that we used. diff --git a/test/api-digester/source-stability.swift.expected b/test/api-digester/source-stability.swift.expected index 59d524405fa49..afef4ce183253 100644 --- a/test/api-digester/source-stability.swift.expected +++ b/test/api-digester/source-stability.swift.expected @@ -58,8 +58,11 @@ Func DefaultRandomAccessIndices.index(after:) has return type change from Elemen Func DefaultRandomAccessIndices.index(before:) has return type change from Elements.Index to DefaultRandomAccessIndices.Index Func Dictionary.index(after:) has return type change from DictionaryIndex to Dictionary.Index Func Dictionary.index(forKey:) has return type change from DictionaryIndex? to Dictionary.Index? +Func Dictionary.makeIterator() has return type change from DictionaryIterator to DictionaryIterator Func Dictionary.popFirst() has return type change from (key: Key, value: Value)? to Dictionary.Element? Func Dictionary.remove(at:) has return type change from (key: Key, value: Value) to Dictionary.Element +Func Dictionary.removeValue(forKey:) has return type change from Value? to Dictionary.Value? +Func Dictionary.updateValue(_:forKey:) has return type change from Value? to Dictionary.Value? Func EnumeratedIterator.next() has return type change from (offset: Int, element: Base.Element)? to EnumeratedIterator.Element? Func FlattenBidirectionalCollection.index(after:) has return type change from FlattenBidirectionalCollectionIndex to FlattenBidirectionalCollection.Index Func FlattenBidirectionalCollection.index(before:) has return type change from FlattenBidirectionalCollectionIndex to FlattenBidirectionalCollection.Index @@ -182,10 +185,22 @@ Func ReversedRandomAccessCollection.index(_:offsetBy:) has return type change fr Func ReversedRandomAccessCollection.index(_:offsetBy:limitedBy:) has return type change from ReversedRandomAccessIndex? to ReversedRandomAccessCollection.Index? Func ReversedRandomAccessCollection.index(after:) has return type change from ReversedRandomAccessIndex to ReversedRandomAccessCollection.Index Func ReversedRandomAccessCollection.index(before:) has return type change from ReversedRandomAccessIndex to ReversedRandomAccessCollection.Index +Func Set.formSymmetricDifference(_:) has 1st parameter type change from Set to Set Func Set.index(after:) has return type change from SetIndex to Set.Index Func Set.index(of:) has return type change from SetIndex? to Set.Index? +Func Set.intersection(_:) has return type change from Set to Set +Func Set.isDisjoint(with:) has 1st parameter type change from Set to Set +Func Set.isStrictSubset(of:) has 1st parameter type change from Set to Set +Func Set.isStrictSuperset(of:) has 1st parameter type change from Set to Set +Func Set.isSubset(of:) has 1st parameter type change from Set to Set +Func Set.isSuperset(of:) has 1st parameter type change from Set to Set Func Set.popFirst() has return type change from Element? to Set.Element? Func Set.remove(at:) has 1st parameter type change from SetIndex to Set.Index +Func Set.removeFirst() has return type change from Element to Set.Element +Func Set.subtract(_:) has 1st parameter type change from Set to Set +Func Set.subtracting(_:) has return type change from Set to Set +Func Set.symmetricDifference(_:) has return type change from Set to Set +Func Set.union(_:) has return type change from Set to Set Func Slice.distance(from:to:) has return type change from Base.IndexDistance to Slice.IndexDistance Func Slice.index(_:offsetBy:) has return type change from Base.Index to Slice.Index Func Slice.index(_:offsetBy:limitedBy:) has return type change from Base.Index? to Slice.Index? diff --git a/validation-test/compiler_scale/enum_members.gyb b/validation-test/compiler_scale/enum_members.gyb new file mode 100644 index 0000000000000..485b5c06d313b --- /dev/null +++ b/validation-test/compiler_scale/enum_members.gyb @@ -0,0 +1,20 @@ +// RUN: %scale-test --sum-multi --typecheck --begin 5 --end 16 --step 5 --select validateDecl %s +// REQUIRES: OS=macosx + +enum Enum${N} { + case OK + case Error + +% if int(N) > 1: + func method(_: Enum${int(N)-1}) {} + static var prop = Enum${int(N)-1}.OK + subscript(n: Int) -> Enum${int(N)-1} { return Enum${int(N)-1}.OK } +% else: + func method() {} + static var prop = 0 + subscript(n: Int) -> Int { return 0 } +% end + + struct Nested {} +} + diff --git a/validation-test/compiler_scale/struct_members.gyb b/validation-test/compiler_scale/struct_members.gyb new file mode 100644 index 0000000000000..9516be0b5d8b8 --- /dev/null +++ b/validation-test/compiler_scale/struct_members.gyb @@ -0,0 +1,18 @@ +// RUN: %scale-test --sum-multi --typecheck --begin 5 --end 16 --step 5 --select validateDecl %s +// REQUIRES: OS=macosx + +struct Struct${N} { +% if int(N) > 1: + func method(_: Struct${int(N)-1}) {} + var prop: Struct${int(N)-1} { return Struct${int(N)-1}() } + static var prop = Struct${int(N)-1}() + subscript(n: Int) -> Struct${int(N)-1} { return Struct${int(N)-1}() } +% else: + func method() {} + var prop: Int { return 0 } + static var prop = 0 + subscript(n: Int) -> Int { return 0 } +% end + + struct Nested {} +}