//===--- Verifier.cpp - AST Invariant Verification ------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements a verifier of AST invariants. // //===----------------------------------------------------------------------===// #include "swift/Subsystems.h" #include "swift/AST/ArchetypeBuilder.h" #include "swift/AST/AST.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Mangle.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/Basic/SourceManager.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" #include using namespace swift; namespace { template struct ASTNodeBase {}; #define EXPR(ID, PARENT) \ template<> \ struct ASTNodeBase { \ typedef PARENT BaseTy; \ }; #define ABSTRACT_EXPR(ID, PARENT) EXPR(ID, PARENT) #include "swift/AST/ExprNodes.def" #define STMT(ID, PARENT) \ template<> \ struct ASTNodeBase { \ typedef PARENT BaseTy; \ }; #include "swift/AST/StmtNodes.def" #define DECL(ID, PARENT) \ template<> \ struct ASTNodeBase { \ typedef PARENT BaseTy; \ }; #define ABSTRACT_DECL(ID, PARENT) DECL(ID, PARENT) #include "swift/AST/DeclNodes.def" #define PATTERN(ID, PARENT) \ template<> \ struct ASTNodeBase { \ typedef PARENT BaseTy; \ }; #include "swift/AST/PatternNodes.def" enum ShouldHalt { Continue, Halt }; class Verifier : public ASTWalker { PointerUnion M; ASTContext &Ctx; llvm::raw_ostream &Out; const bool HadError; SmallVector InImplicitBraceStmt; /// \brief The stack of functions we're visiting. SmallVector Functions; /// \brief The stack of scopes we're visiting. using ScopeLike = llvm::PointerUnion; SmallVector Scopes; /// \brief The stack of optional evaluations active at this point. SmallVector OptionalEvaluations; /// \brief The set of opaque value expressions active at this point. llvm::DenseMap OpaqueValues; /// The set of opened existential archetypes that are currently /// active. llvm::DenseSet OpenedExistentialArchetypes; /// A key into ClosureDiscriminators is a combination of a /// ("canonicalized") local DeclContext* and a flag for whether to /// use the explicit closure sequence (false) or the implicit /// closure sequence (true). typedef llvm::PointerIntPair ClosureDiscriminatorKey; llvm::DenseMap ClosureDiscriminators; DeclContext *CanonicalTopLevelContext = nullptr; public: Verifier(Module *M, DeclContext *DC) : M(M), Ctx(M->Ctx), Out(llvm::errs()), HadError(M->Ctx.hadError()) { Scopes.push_back(DC); } Verifier(SourceFile &SF, DeclContext *DC) : M(&SF), Ctx(SF.getASTContext()), Out(llvm::errs()), HadError(SF.getASTContext().hadError()) { Scopes.push_back(DC); } static Verifier forDecl(const Decl *D) { DeclContext *DC = D->getDeclContext(); DeclContext *topDC = DC->getModuleScopeContext(); if (auto SF = dyn_cast(topDC)) return Verifier(*SF, DC); return Verifier(topDC->getParentModule(), DC); } std::pair walkToExprPre(Expr *E) override { switch (E->getKind()) { #define DISPATCH(ID) return dispatchVisitPreExpr(static_cast(E)) #define EXPR(ID, PARENT) \ case ExprKind::ID: \ DISPATCH(ID); #define UNCHECKED_EXPR(ID, PARENT) \ case ExprKind::ID: \ assert((HadError || !M.is() || \ M.get()->ASTStage < SourceFile::TypeChecked) && \ #ID "in wrong phase");\ DISPATCH(ID); #include "swift/AST/ExprNodes.def" #undef DISPATCH } llvm_unreachable("not all cases handled!"); } Expr *walkToExprPost(Expr *E) override { switch (E->getKind()) { #define DISPATCH(ID) return dispatchVisitPost(static_cast(E)) #define EXPR(ID, PARENT) \ case ExprKind::ID: \ DISPATCH(ID); #define UNCHECKED_EXPR(ID, PARENT) \ case ExprKind::ID: \ assert((HadError || !M.is() || \ M.get()->ASTStage < SourceFile::TypeChecked) && \ #ID "in wrong phase");\ DISPATCH(ID); #include "swift/AST/ExprNodes.def" #undef DISPATCH } llvm_unreachable("not all cases handled!"); } std::pair walkToStmtPre(Stmt *S) override { switch (S->getKind()) { #define DISPATCH(ID) return dispatchVisitPreStmt(static_cast(S)) #define STMT(ID, PARENT) \ case StmtKind::ID: \ DISPATCH(ID); #include "swift/AST/StmtNodes.def" #undef DISPATCH } llvm_unreachable("not all cases handled!"); } Stmt *walkToStmtPost(Stmt *S) override { switch (S->getKind()) { #define DISPATCH(ID) return dispatchVisitPost(static_cast(S)) #define STMT(ID, PARENT) \ case StmtKind::ID: \ DISPATCH(ID); #include "swift/AST/StmtNodes.def" #undef DISPATCH } llvm_unreachable("not all cases handled!"); } std::pair walkToPatternPre(Pattern *P) override { switch (P->getKind()) { #define DISPATCH(ID) \ return dispatchVisitPrePattern(static_cast(P)) #define PATTERN(ID, PARENT) \ case PatternKind::ID: \ DISPATCH(ID); #include "swift/AST/PatternNodes.def" #undef DISPATCH } llvm_unreachable("not all cases handled!"); } Pattern *walkToPatternPost(Pattern *P) { switch (P->getKind()) { #define DISPATCH(ID) \ return dispatchVisitPost(static_cast(P)) #define PATTERN(ID, PARENT) \ case PatternKind::ID: \ DISPATCH(ID); #include "swift/AST/PatternNodes.def" #undef DISPATCH } llvm_unreachable("not all cases handled!"); } bool walkToDeclPre(Decl *D) override { switch (D->getKind()) { #define DISPATCH(ID) return dispatchVisitPre(static_cast(D)) #define DECL(ID, PARENT) \ case DeclKind::ID: \ DISPATCH(ID); #include "swift/AST/DeclNodes.def" #undef DISPATCH } llvm_unreachable("not all cases handled!"); } bool walkToDeclPost(Decl *D) override { switch (D->getKind()) { #define DISPATCH(ID) return dispatchVisitPost(static_cast(D)) #define DECL(ID, PARENT) \ case DeclKind::ID: \ DISPATCH(ID); #include "swift/AST/DeclNodes.def" #undef DISPATCH } llvm_unreachable("Unhandled declaratiom kind"); } private: /// Helper template for dispatching pre-visitation. /// If we're visiting in pre-order, don't validate the node yet; /// just check whether we should stop further descent. template bool dispatchVisitPre(T node) { return shouldVerify(node); } /// Helper template for dispatching pre-visitation. /// If we're visiting in pre-order, don't validate the node yet; /// just check whether we should stop further descent. template std::pair dispatchVisitPreExpr(T node) { return { shouldVerify(node), node }; } /// Helper template for dispatching pre-visitation. /// If we're visiting in pre-order, don't validate the node yet; /// just check whether we should stop further descent. template std::pair dispatchVisitPreStmt(T node) { return { shouldVerify(node), node }; } /// Helper template for dispatching pre-visitation. /// If we're visiting in pre-order, don't validate the node yet; /// just check whether we should stop further descent. template std::pair dispatchVisitPrePattern(T node) { return { shouldVerify(node), node }; } /// Helper template for dispatching post-visitation. template T dispatchVisitPost(T node) { // Verify source ranges if the AST node was parsed from source. SourceFile *SF = M.dyn_cast(); if (SF) { // If we are inside an implicit BraceStmt, don't verify source // locations. LLDB creates implicit BraceStmts which contain a mix of // generated/user-written code. if (InImplicitBraceStmt.empty() || !InImplicitBraceStmt.back()) checkSourceRanges(node); } // Check that nodes marked invalid have the correct type. checkErrors(node); // Always verify the node as a parsed node. verifyParsed(node); // If we've bound names already, verify as a bound node. if (!SF || SF->ASTStage >= SourceFile::NameBound) verifyBound(node); // If we've checked types already, do some extra verification. if (!SF || SF->ASTStage >= SourceFile::TypeChecked) { verifyCheckedAlways(node); if (!HadError) verifyChecked(node); } // Clean up anything that we've placed into a stack to check. cleanup(node); // Always continue. return node; } // Default cases for whether we should verify within the given subtree. bool shouldVerify(Expr *E) { return true; } bool shouldVerify(Stmt *S) { return true; } bool shouldVerify(Pattern *S) { return true; } bool shouldVerify(Decl *S) { return true; } // Default cases for cleaning up as we exit a node. void cleanup(Expr *E) { } void cleanup(Stmt *S) { } void cleanup(Pattern *P) { } void cleanup(Decl *D) { } // Base cases for the various stages of verification. void verifyParsed(Expr *E) {} void verifyParsed(Stmt *S) {} void verifyParsed(Pattern *P) {} void verifyParsed(Decl *D) { if (!D->getDeclContext()) { Out << "every Decl should have a DeclContext"; PrettyStackTraceDecl debugStack("verifying DeclContext", D); abort(); } if (D->getAttrs().hasAttribute()) { if (!isa(D) && !isa(D) && !isa(D)) { PrettyStackTraceDecl debugStack("verifying override", D); Out << "'override' attribute on a non-overridable member\n"; D->dump(Out); abort(); } } } template void verifyParsedBase(T ASTNode) { verifyParsed(cast::BaseTy>(ASTNode)); } void verifyBound(Expr *E) {} void verifyBound(Stmt *S) {} void verifyBound(Pattern *P) {} void verifyBound(Decl *D) {} /// @{ /// These verification functions are always run on type checked ASTs /// (even if there were errors). void verifyCheckedAlways(Expr *E) {} void verifyCheckedAlways(Stmt *S) {} void verifyCheckedAlways(Pattern *P) {} void verifyCheckedAlways(Decl *D) { if (!D->isInvalid() && D->getAttrs().hasAttribute()) { if (!isa(D->getDeclContext()) && !isa(D->getDeclContext())) { PrettyStackTraceDecl debugStack("verifying override", D); Out << "'override' attribute outside of a class\n"; D->dump(Out); abort(); } } } template void verifyCheckedAlwaysBase(T ASTNode) { verifyCheckedAlways(cast::BaseTy>(ASTNode)); } /// @} /// @{ /// These verification functions are run on type checked ASTs if there were /// no errors. void verifyChecked(Expr *E) { bool failed = E->getType().findIf([&](Type type) -> bool { if (auto archetypeTy = type->getAs()) { if (archetypeTy->getOpenedExistentialType()) { if (OpenedExistentialArchetypes.count(archetypeTy) == 0) { Out << "Found opened existential archetype " << archetypeTy->getString() << " outside enclosing OpenExistentialExpr\n"; E->dump(Out); return true; } } } return false; }); if (failed) assert(false); } void verifyChecked(Stmt *S) {} void verifyChecked(Pattern *P) {} void verifyChecked(Decl *D) {} template void verifyCheckedBase(T ASTNode) { verifyChecked(cast::BaseTy>(ASTNode)); } /// @} // Specialized verifiers. template void pushScope(T *scope) { Scopes.push_back(scope); } void popScope(DeclContext *scope) { assert(Scopes.back().get() == scope); Scopes.pop_back(); } void popScope(BraceStmt *scope) { assert(Scopes.back().get() == scope); Scopes.pop_back(); } void pushFunction(DeclContext *functionScope) { pushScope(functionScope); Functions.push_back(functionScope); } void popFunction(DeclContext *functionScope) { assert(Functions.back() == functionScope); Functions.pop_back(); popScope(functionScope); } #define FUNCTION_LIKE(NODE) \ bool shouldVerify(NODE *fn) { \ pushFunction(fn); \ return shouldVerify(cast::BaseTy>(fn));\ } \ void cleanup(NODE *fn) { \ popFunction(fn); \ } #define SCOPE_LIKE(NODE) \ bool shouldVerify(NODE *fn) { \ pushScope(fn); \ if (fn->hasLazyMembers()) \ return false; \ return shouldVerify(cast::BaseTy>(fn));\ } \ void cleanup(NODE *fn) { \ popScope(fn); \ } FUNCTION_LIKE(AbstractClosureExpr) FUNCTION_LIKE(ConstructorDecl) FUNCTION_LIKE(DestructorDecl) FUNCTION_LIKE(FuncDecl) SCOPE_LIKE(NominalTypeDecl) SCOPE_LIKE(ExtensionDecl) #undef SCOPE_LIKE #undef FUNCTION_LIKE bool shouldVerify(BraceStmt *BS) { pushScope(BS); InImplicitBraceStmt.push_back(BS->isImplicit()); return shouldVerify(cast(BS)); } void cleanup(BraceStmt *BS) { InImplicitBraceStmt.pop_back(); popScope(BS); } bool shouldVerify(OpenExistentialExpr *expr) { if (!shouldVerify(cast(expr))) return false; OpaqueValues[expr->getOpaqueValue()] = 0; assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==0); OpenedExistentialArchetypes.insert(expr->getOpenedArchetype()); return true; } void cleanup(OpenExistentialExpr *expr) { OpaqueValues.erase(expr->getOpaqueValue()); assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==1); OpenedExistentialArchetypes.erase(expr->getOpenedArchetype()); } // Keep a stack of the currently-live optional evaluations. bool shouldVerify(OptionalEvaluationExpr *expr) { if (!shouldVerify(cast(expr))) return false; OptionalEvaluations.push_back(expr); return true; } void cleanup(OptionalEvaluationExpr *expr) { assert(OptionalEvaluations.back() == expr); OptionalEvaluations.pop_back(); } /// Canonicalize the given DeclContext pointer, in terms of /// producing something that can be looked up in /// ClosureDiscriminators. DeclContext *getCanonicalDeclContext(DeclContext *DC) { // All we really need to do is use a single TopLevelCodeDecl. if (auto topLevel = dyn_cast(DC)) { if (!CanonicalTopLevelContext) CanonicalTopLevelContext = topLevel; return CanonicalTopLevelContext; } // TODO: check for uniqueness of initializer contexts? return DC; } /// Return the appropriate discriminator set for a closure expression. llvm::SmallBitVector &getClosureDiscriminators(AbstractClosureExpr *closure) { auto dc = getCanonicalDeclContext(closure->getParent()); bool isAutoClosure = isa(closure); return ClosureDiscriminators[ClosureDiscriminatorKey(dc, isAutoClosure)]; } void verifyCheckedAlways(ValueDecl *D) { if (D->hasName()) checkMangling(D); if (D->hasType() && D->getType()->hasTypeVariable()) { PrettyStackTraceDecl debugStack("verifying type variable", D); Out << "a type variable escaped the type checker"; D->dump(Out); abort(); } if (auto Overridden = D->getOverriddenDecl()) { if (D->getDeclContext() == Overridden->getDeclContext()) { PrettyStackTraceDecl debugStack("verifying overriden", D); Out << "can not override a decl in the same DeclContext"; D->dump(Out); Overridden->dump(Out); abort(); } } if (D->conformsToProtocolRequirement()) { if (D->getConformances().empty()) { PrettyStackTraceDecl debugStack("checking conformances", D); Out << "conforms bit set but no conformances found\n"; D->dump(Out); abort(); } } verifyCheckedAlwaysBase(D); } void verifyCheckedAlways(NominalTypeDecl *D) { checkMangling(D); verifyCheckedAlwaysBase(D); } void verifyChecked(ReturnStmt *S) { auto func = Functions.back(); Type resultType; if (FuncDecl *FD = dyn_cast(func)) { resultType = FD->getResultType(); } else if (auto closure = dyn_cast(func)) { resultType = closure->getResultType(); } else { resultType = TupleType::getEmpty(Ctx); } if (S->hasResult()) { auto result = S->getResult(); auto returnType = result->getType(); // Make sure that the return has the same type as the function. checkSameType(resultType, returnType, "return type"); } else { // Make sure that the function has a Void result type. checkSameType(resultType, TupleType::getEmpty(Ctx), "return type"); } verifyCheckedBase(S); } void checkCondition(StmtCondition C) { if (auto E = C.dyn_cast()) { checkSameType(E->getType(), BuiltinIntegerType::get(1, Ctx), "condition type"); return; } if (auto CB = C.dyn_cast()) { PrettyStackTraceDecl debugStack("verifying condition binding", CB); if (!CB->isConditional()) { Out << "condition binding is not conditional\n"; CB->print(Out); abort(); } if (!CB->getInit()) { Out << "conditional binding does not have initializer\n"; CB->print(Out); abort(); } auto initOptionalType = CB->getInit()->getType(); auto initType = initOptionalType->getAnyOptionalObjectType(); if (!initType) { Out << "conditional binding is not of optional type\n"; CB->print(Out); abort(); } checkSameType(CB->getPattern()->getType(), initType, "conditional binding type"); } } void verifyChecked(IfStmt *S) { checkCondition(S->getCond()); verifyCheckedBase(S); } void verifyChecked(WhileStmt *S) { checkCondition(S->getCond()); verifyCheckedBase(S); } Type checkAssignDest(Expr *Dest) { if (TupleExpr *TE = dyn_cast(Dest)) { SmallVector lhsTupleTypes; for (unsigned i = 0; i != TE->getNumElements(); ++i) { Type SubType = checkAssignDest(TE->getElement(i)); lhsTupleTypes.push_back(TupleTypeElt(SubType, TE->getElementName(i))); } return TupleType::get(lhsTupleTypes, Ctx); } return checkLValue(Dest->getType(), "LHS of assignment"); } void verifyChecked(DeclRefExpr *E) { if (E->getType()->is()) { PrettyStackTraceExpr debugStack(Ctx, "verifying decl reference", E); Out << "unspecialized reference with polymorphic type " << E->getType().getString() << "\n"; E->dump(Out); abort(); } verifyCheckedBase(E); } void verifyChecked(AssignExpr *S) { Type lhsTy = checkAssignDest(S->getDest()); checkSameType(lhsTy, S->getSrc()->getType(), "assignment operands"); verifyCheckedBase(S); } void verifyChecked(InOutExpr *E) { Type srcObj = checkLValue(E->getSubExpr()->getType(), "result of InOutExpr"); auto DestTy = E->getType()->castTo()->getObjectType(); checkSameType(DestTy, srcObj, "object types for InOutExpr"); verifyCheckedBase(E); } void verifyParsed(AbstractClosureExpr *E) { Type Ty = E->getType(); if (!Ty) return; if (Ty->is()) return; if (!Ty->is()) { PrettyStackTraceExpr debugStack(Ctx, "verifying closure", E); Out << "a closure should have a function type"; E->print(Out); Out << "\n"; abort(); } verifyParsedBase(E); } void verifyChecked(AbstractClosureExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying closure", E); assert(Scopes.back().get() == E); assert(E->getParent()->isLocalContext() && "closure expression was not in local context!"); // Check that the discriminator is unique in its context. auto &discriminatorSet = getClosureDiscriminators(E); unsigned discriminator = E->getDiscriminator(); if (discriminator >= discriminatorSet.size()) { discriminatorSet.resize(discriminator+1); discriminatorSet.set(discriminator); } else if (discriminatorSet.test(discriminator)) { Out << "a closure must have a unique discriminator in its context\n"; E->print(Out); Out << "\n"; abort(); } else { discriminatorSet.set(discriminator); } // If the enclosing scope is a DC directly, rather than a local scope, // then the closure should be parented by an Initializer. Otherwise, // it should be parented by the innermost function. auto enclosingScope = Scopes[Scopes.size() - 2]; auto enclosingDC = enclosingScope.dyn_cast(); if (enclosingDC && !isa(enclosingDC) && !(isa(enclosingDC) && cast(enclosingDC)->Kind == SourceFileKind::REPL)){ auto parentDC = E->getParent(); if (!isa(parentDC)) { Out << "a closure in non-local context should be parented " "by an initializer or REPL context"; E->print(Out); Out << "\n"; abort(); } else if (parentDC->getParent() != enclosingDC) { Out << "closure in non-local context not grandparented by its " "enclosing function"; E->print(Out); Out << "\n"; abort(); } } else if (Functions.size() >= 2 && Functions[Functions.size() - 2] != E->getParent()) { Out << "closure in local context not parented by its " "enclosing function"; E->print(Out); Out << "\n"; abort(); } if (E->getDiscriminator() == AbstractClosureExpr::InvalidDiscriminator) { Out << "a closure expression should have a valid discriminator\n"; E->print(Out); Out << "\n"; abort(); } } void verifyChecked(MetatypeConversionExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying MetatypeConversion", E); auto destTy = checkMetatypeType(E->getType(), "result of MetatypeConversionExpr"); auto srcTy = checkMetatypeType(E->getSubExpr()->getType(), "source of MetatypeConversionExpr"); if (destTy->isEqual(srcTy)) { Out << "trivial MetatypeConversionExpr:\n"; E->print(Out); Out << "\n"; abort(); } checkTrivialSubtype(srcTy, destTy, "MetatypeConversionExpr"); verifyCheckedBase(E); } void verifyChecked(ArrayUpcastConversionExpr *E) { verifyChecked(E->getSubExpr()); verifyCheckedBase(E); } void verifyChecked(ArrayBridgedConversionExpr *E) { verifyChecked(E->getSubExpr()); verifyCheckedBase(E); } void verifyChecked(DerivedToBaseExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying DerivedToBaseExpr", E); auto destTy = E->getType(); auto srcTy = E->getSubExpr()->getType(); if (destTy->isEqual(srcTy)) { Out << "trivial DerivedToBaseExpr:\n"; E->print(Out); Out << "\n"; abort(); } if (!destTy->getClassOrBoundGenericClass() || !(srcTy->getClassOrBoundGenericClass() || srcTy->is())) { Out << "DerivedToBaseExpr does not involve class types:\n"; E->print(Out); Out << "\n"; abort(); } checkTrivialSubtype(srcTy, destTy, "DerivedToBaseExpr"); verifyCheckedBase(E); } void verifyChecked(TupleElementExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying TupleElementExpr", E); Type resultType = E->getType(); Type baseType = E->getBase()->getType(); checkSameLValueness(baseType, resultType, "base and result of TupleElementExpr"); TupleType *tupleType = baseType->getAs(); if (!tupleType) { Out << "base of TupleElementExpr does not have tuple type: "; E->getBase()->getType().print(Out); Out << "\n"; abort(); } if (E->getFieldNumber() >= tupleType->getFields().size()) { Out << "field index " << E->getFieldNumber() << " for TupleElementExpr is out of range [0," << tupleType->getFields().size() << ")\n"; abort(); } checkSameType(resultType, tupleType->getElementType(E->getFieldNumber()), "TupleElementExpr and the corresponding tuple element"); verifyCheckedBase(E); } void verifyChecked(ApplyExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying ApplyExpr", E); FunctionType *FT = E->getFn()->getType()->getAs(); if (!FT) { Out << "callee of apply expression does not have function type:"; E->getFn()->getType().print(Out); Out << "\n"; abort(); } CanType InputExprTy = E->getArg()->getType()->getCanonicalType(); CanType ResultExprTy = E->getType()->getCanonicalType(); if (ResultExprTy != FT->getResult()->getCanonicalType()) { Out << "result of ApplyExpr does not match result type of callee:"; E->getType().print(Out); Out << " vs. "; FT->getResult()->print(Out); Out << "\n"; abort(); } if (InputExprTy != FT->getInput()->getCanonicalType()) { TupleType *TT = FT->getInput()->getAs(); if (isa(E)) { Type InputExprObjectTy; if (InputExprTy->hasReferenceSemantics() || InputExprTy->is()) InputExprObjectTy = InputExprTy; else InputExprObjectTy = checkLValue(InputExprTy, "object argument"); Type FunctionInputObjectTy = checkLValue(FT->getInput(), "'self' parameter"); checkSameOrSubType(InputExprObjectTy, FunctionInputObjectTy, "object argument and 'self' parameter"); } else if (!TT || TT->getFields().size() != 1 || TT->getFields()[0].getType()->getCanonicalType() != InputExprTy) { Out << "Argument type does not match parameter type in ApplyExpr:" "\nArgument type: "; E->getArg()->getType().print(Out); Out << "\nParameter type: "; FT->getInput()->print(Out); Out << "\n"; E->dump(Out); abort(); } } if (E->isSuper() != E->getArg()->isSuperExpr()) { Out << "Function application's isSuper() bit mismatch.\n"; E->dump(Out); abort(); } verifyCheckedBase(E); } void verifyChecked(MemberRefExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying MemberRefExpr", E); if (!E->getMember()) { Out << "Member reference is missing declaration\n"; E->dump(Out); abort(); } // The only time the base is allowed to be inout is if we are accessing // a computed property or if the base is a protocol or existential. if (auto *baseIOT = E->getBase()->getType()->getAs()) { if (!baseIOT->getObjectType()->isExistentialType() && !baseIOT->getObjectType()->is()) { VarDecl *VD = dyn_cast(E->getMember().getDecl()); if (!VD || !VD->hasAccessorFunctions()) { Out << "member_ref_expr on value of inout type\n"; E->dump(Out); abort(); } } } // FIXME: Check container/member types through substitutions. verifyCheckedBase(E); } void verifyChecked(DynamicMemberRefExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying DynamicMemberRefExpr", E); // The base type must be AnyObject. auto baseTy = E->getBase()->getType(); // The base might be a metatype of AnyObject. if (auto baseMetaTy = baseTy->getAs()) { baseTy = baseMetaTy->getInstanceType(); } auto baseProtoTy = baseTy->getAs(); if (!baseProtoTy || !baseProtoTy->getDecl()->isSpecificProtocol( KnownProtocolKind::AnyObject)) { Out << "Dynamic member reference has non-AnyObject base\n"; E->dump(Out); abort(); } // The member must be [objc]. if (!E->getMember().getDecl()->isObjC()) { Out << "Dynamic member reference to non-[objc] member\n"; E->dump(Out); abort(); } verifyCheckedBase(E); } void verifyChecked(SubscriptExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying SubscriptExpr", E); if (!E->getDecl()) { Out << "Subscript expression is missing subscript declaration"; abort(); } // FIXME: Check base/member types through substitutions. verifyCheckedBase(E); } void verifyChecked(BindOptionalExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying BindOptionalExpr", E); if (E->getDepth() >= OptionalEvaluations.size()) { Out << "BindOptional expression is out of its depth"; abort(); } verifyCheckedBase(E); } void verifyChecked(CheckedCastExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying CheckCastExpr", E); if (!E->isResolved()) { Out << "CheckedCast kind not resolved\n"; abort(); } verifyCheckedBase(E); } void verifyChecked(CoerceExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying CoerceExpr", E); checkSameType(E->getType(), E->getSubExpr()->getType(), "coercion type and subexpression type"); verifyCheckedBase(E); } void verifyChecked(TupleShuffleExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying TupleShuffleExpr", E); TupleType *TT = E->getType()->getAs(); TupleType *SubTT = E->getSubExpr()->getType()->getAs(); if (!TT || !SubTT) { Out << "Unexpected types in TupleShuffleExpr\n"; abort(); } unsigned varargsStartIndex = 0; Type varargsType; unsigned callerDefaultArgIndex = 0; for (unsigned i = 0, e = E->getElementMapping().size(); i != e; ++i) { int subElem = E->getElementMapping()[i]; if (subElem == TupleShuffleExpr::DefaultInitialize) continue; if (subElem == TupleShuffleExpr::FirstVariadic) { varargsStartIndex = i + 1; varargsType = TT->getFields()[i].getVarargBaseTy(); break; } if (subElem == TupleShuffleExpr::CallerDefaultInitialize) { auto init = E->getCallerDefaultArgs()[callerDefaultArgIndex++]; if (!TT->getElementType(i)->isEqual(init->getType())) { Out << "Type mismatch in TupleShuffleExpr\n"; abort(); } continue; } if (!TT->getElementType(i)->isEqual(SubTT->getElementType(subElem))) { Out << "Type mismatch in TupleShuffleExpr\n"; abort(); } } if (varargsStartIndex) { unsigned i = varargsStartIndex, e = E->getElementMapping().size(); for (; i != e; ++i) { unsigned subElem = E->getElementMapping()[i]; if (!SubTT->getElementType(subElem)->isEqual(varargsType)) { Out << "Vararg type mismatch in TupleShuffleExpr\n"; abort(); } } } verifyCheckedBase(E); } void verifyChecked(LValueConversionExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying LValueConversionExpr", E); if (!E->getSubExpr()->getType()->is()) { Out << "LValueConversion subexpression must be an lvalue\n"; abort(); } if (!E->getType()->is()) { Out << "LValueConversion result type must be an lvalue\n"; abort(); } Type origType = E->getSubExpr()->getType()->getLValueOrInOutObjectType(); Type convertedType = E->getType()->getLValueOrInOutObjectType(); auto fromFnType = E->getFromConversionFn()->getType()->getAs(); if (!fromFnType) { Out << "LValueConversion from-conversion function must be of function " "type\n"; abort(); } if (!fromFnType->getResult()->isEqual(convertedType)) { Out << "LValueConversion from-conversion function must return the " "converted type\n"; abort(); } auto inputTypeMatches = [&](Type input, Type expected) -> bool { if (input->isEqual(expected)) return true; auto tup = input->getAs(); if (!tup) return false; if (tup->getNumElements() != 1) return false; if (tup->getFields()[0].isVararg()) return false; return tup->getFields()[0].getType()->isEqual(expected); }; if (!inputTypeMatches(fromFnType->getInput(), origType)) { Out << "LValueConversion from-conversion function must take the " "original type as its parameter\n"; abort(); } auto toFnType = E->getToConversionFn()->getType()->getAs(); if (!toFnType) { Out << "LValueConversion to-conversion function must be of function " "type\n"; abort(); } if (!toFnType->getResult()->isEqual(origType)) { Out << "LValueConversion to-conversion function must return the " "orig type\n"; abort(); } if (!inputTypeMatches(toFnType->getInput(), convertedType)) { Out << "LValueConversion to-conversion function must take the " "converted type as its parameter\n"; abort(); } verifyCheckedBase(E); } void verifyChecked(LValueToPointerExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying LValueToPointerExpr", E); if (!E->getSubExpr()->getType()->is()) { Out << "LValueToPointerExpr subexpression must be an lvalue\n"; abort(); } if (!E->getType()->isEqual( E->getType()->getASTContext().TheRawPointerType)) { Out << "LValueToPointerExpr result type must be RawPointer\n"; abort(); } verifyCheckedBase(E); } void verifyChecked(InOutConversionExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying InOutConversionExpr", E); if (!E->getSubExpr()->getType()->isEqual(E->getType())) { Out << "InOutConversionExpr must have the same type as its subexpression\n"; abort(); } verifyCheckedBase(E); } void verifyChecked(DynamicTypeExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying DynamicTypeExpr", E); auto metatype = E->getType()->getAs(); if (!metatype) { Out << "DynamicTypeExpr must have metatype type\n"; abort(); } checkSameType(E->getBase()->getType(), metatype->getInstanceType(), "base type of .Type expression"); verifyCheckedBase(E); } void verifyParsed(NewArrayExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying NewArrayExpr", E); if (E->getBounds().empty()) { Out << "NewArrayExpr has an empty bounds list\n"; abort(); } if (E->getBounds()[0].Value == nullptr) { Out << "First bound of NewArrayExpr is missing\n"; abort(); } verifyParsedBase(E); } void verifyChecked(NewArrayExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying NewArrayExpr", E); if (!E->hasElementType()) { Out << "NewArrayExpr is missing its element type"; abort(); } if (!E->hasInjectionFunction()) { Out << "NewArrayExpr is missing an injection function"; abort(); } verifyCheckedBase(E); } void verifyChecked(InjectIntoOptionalExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying InjectIntoOptionalExpr", E); auto valueType = E->getType()->getAnyOptionalObjectType(); if (!valueType) { Out << "InjectIntoOptionalExpr is not of Optional type"; abort(); } if (!E->getSubExpr()->getType()->isEqual(valueType)) { Out << "InjectIntoOptionalExpr operand is not of the value type"; abort(); } verifyCheckedBase(E); } void verifyChecked(IfExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying IfExpr", E); auto condTy = E->getCondExpr()->getType()->getAs(); if (!condTy || !condTy->isFixedWidth() || condTy->getFixedWidth() != 1) { Out << "IfExpr condition is not an i1\n"; abort(); } checkSameType(E->getThenExpr()->getType(), E->getElseExpr()->getType(), "then and else branches of an if-expr"); verifyCheckedBase(E); } void verifyChecked(SuperRefExpr *expr) { verifyCheckedBase(expr); } void verifyChecked(TypeExpr *expr) { if (!expr->getType()->getAs()) { Out << "TypeExpr must have metatype type\n"; abort(); } verifyCheckedBase(expr); } void verifyChecked(ForceValueExpr *E) { auto valueTy = E->getType(); auto optValueTy = E->getSubExpr()->getType()->getAnyOptionalObjectType(); checkSameType(valueTy, optValueTy, "optional value type"); verifyCheckedBase(E); } void verifyChecked(OpaqueValueExpr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying OpaqueValueExpr", E); if (!OpaqueValues.count(E)) { Out << "OpaqueValueExpr not introduced at this point in AST\n"; abort(); } ++OpaqueValues[E]; // Make sure "uniquely-referenced" actually is. if (E->isUniquelyReferenced() && OpaqueValues[E] > 1) { Out << "Multiple references to unique OpaqueValueExpr\n"; abort(); } verifyCheckedBase(E); } void verifyChecked(PatternBindingDecl *binding) { } void verifyChecked(VarDecl *var) { PrettyStackTraceDecl debugStack("verifying VarDecl", var); // The fact that this is *directly* be a reference storage type // cuts the code down quite a bit in getTypeOfReference. if (var->getAttrs().hasOwnership() != isa(var->getType().getPointer())) { if (var->getAttrs().hasOwnership()) { Out << "VarDecl has an ownership attribute, but its type" " is not a ReferenceStorageType: "; } else { Out << "VarDecl has no ownership attribute, but its type" " is a ReferenceStorageType: "; } var->getType().print(Out); abort(); } verifyCheckedBase(var); } // Dump a reference to the given declaration. void dumpRef(Decl *decl) { if (auto value = dyn_cast(decl)) value->dumpRef(Out); else if (auto ext = dyn_cast(decl)) { Out << "extension of "; if (ext->getExtendedType()) ext->getExtendedType().print(Out); } } /// Check the given list of protocols. void verifyProtocolList(Decl *decl, ArrayRef protocols) { PrettyStackTraceDecl debugStack("verifying ProtocolList", decl); // Make sure that the protocol list is fully expanded. SmallVector nominalProtocols(protocols.begin(), protocols.end()); ProtocolType::canonicalizeProtocols(nominalProtocols); SmallVector protocolTypes; for (auto proto : protocols) protocolTypes.push_back(proto->getDeclaredType()); SmallVector canonicalProtocols; ProtocolCompositionType::get(Ctx, protocolTypes) ->isExistentialType(canonicalProtocols); if (nominalProtocols != canonicalProtocols) { dumpRef(decl); Out << " doesn't have a complete set of protocols\n"; abort(); } } /// Check the given explicit protocol conformance. void verifyConformance(Decl *decl, ProtocolConformance *conformance) { PrettyStackTraceDecl debugStack("verifying protocol conformance", decl); if (!conformance) { // FIXME: Eventually, this should itself be a verification // failure. return; } switch (conformance->getState()) { case ProtocolConformanceState::Complete: case ProtocolConformanceState::Invalid: // More checking below. break; case ProtocolConformanceState::Incomplete: dumpRef(decl); Out << " has a known-incomplete conformance for protocol " << conformance->getProtocol()->getName().str() << "\n"; abort(); } auto normal = dyn_cast(conformance); if (!normal) return; // Check that a normal protocol conformance is complete. auto proto = conformance->getProtocol(); for (auto member : proto->getMembers()) { if (auto assocType = dyn_cast(member)) { if (!normal->hasTypeWitness(assocType)) { dumpRef(decl); Out << " is missing type witness for " << conformance->getProtocol()->getName().str() << "." << assocType->getName().str() << "\n"; abort(); } continue; } // If this is a getter/setter for a funcdecl, ignore it. if (auto *FD = dyn_cast(member)) if (FD->isGetterOrSetter()) continue; if (auto req = dyn_cast(member)) { if (!normal->hasWitness(req)) { dumpRef(decl); Out << " is missing witness for " << conformance->getProtocol()->getName().str() << "." << req->getName().str() << "\n"; abort(); } continue; } } } void verifyChecked(NominalTypeDecl *nominal) { // Make sure that the protocol list is fully expanded. verifyProtocolList(nominal, nominal->getProtocols()); // Make sure that the protocol conformances are complete. for (auto conformance : nominal->getConformances()) { verifyConformance(nominal, conformance); } verifyCheckedBase(nominal); } void verifyChecked(ExtensionDecl *ext) { // Make sure that the protocol list is fully expanded. verifyProtocolList(ext, ext->getProtocols()); // Make sure that the protocol conformances are complete. for (auto conformance : ext->getConformances()) { verifyConformance(ext, conformance); } verifyCheckedBase(ext); } void verifyParsed(EnumElementDecl *UED) { PrettyStackTraceDecl debugStack("verifying EnumElementDecl", UED); if (!isa(UED->getDeclContext())) { Out << "EnumElementDecl has wrong DeclContext"; abort(); } verifyParsedBase(UED); } void verifyParsed(AbstractFunctionDecl *AFD) { PrettyStackTraceDecl debugStack("verifying AbstractFunctionDecl", AFD); verifyParsedBase(AFD); } void verifyParsed(ConstructorDecl *CD) { PrettyStackTraceDecl debugStack("verifying ConstructorDecl", CD); if (CD->getBodyParamPatterns().size() != 2) { Out << "ConstructorDecl should have exactly two parameter patterns"; abort(); } auto *DC = CD->getDeclContext(); if (!isa(DC) && !isa(DC) && !CD->isInvalid()) { Out << "ConstructorDecls outside nominal types and extensions " "should be marked invalid"; abort(); } verifyParsedBase(CD); } void verifyChecked(ProtocolDecl *PD) { PrettyStackTraceDecl debugStack("verifying ProtocolDecl", PD); if (PD->isObjC() && !PD->requiresClass()) { Out << "@objc protocols should be class protocols as well"; abort(); } verifyCheckedBase(PD); } void verifyChecked(ConstructorDecl *CD) { PrettyStackTraceDecl debugStack("verifying ConstructorDecl", CD); auto *ND = CD->getExtensionType()->getNominalOrBoundGenericNominal(); if (!isa(ND) && !isa(ND) && !isa(ND) && !isa(ND) && !CD->isInvalid()) { Out << "ConstructorDecls outside structs, classes or enums " "should be marked invalid"; abort(); } verifyCheckedBase(CD); } void verifyParsed(DestructorDecl *DD) { PrettyStackTraceDecl debugStack("verifying DestructorDecl", DD); if (DD->isGeneric()) { Out << "DestructorDecl can not be generic"; abort(); } if (DD->getBodyParamPatterns().size() != 1) { Out << "DestructorDecl should have 'self' parameter pattern only"; abort(); } auto *DC = DD->getDeclContext(); if (!isa(DC) && !isa(DC) && !DD->isInvalid()) { Out << "DestructorDecls outside nominal types and extensions " "should be marked invalid"; abort(); } verifyParsedBase(DD); } bool checkAllArchetypes(const GenericParamList *generics) { ArrayRef storedArchetypes = generics->getAllArchetypes(); SmallVector derivedBuffer; ArrayRef derivedArchetypes = GenericParamList::deriveAllArchetypes(generics->getParams(), derivedBuffer); return (storedArchetypes == derivedArchetypes); } /// Check that the generic requirements line up with the archetypes. void checkGenericRequirements(Decl *decl, DeclContext *dc, GenericFunctionType *genericTy) { PrettyStackTraceDecl debugStack("verifying generic requirements", decl); // We need to have generic parameters here. auto genericParams = dc->getGenericParamsOfContext(); if (!genericParams) { Out << "Missing generic parameters\n"; decl->dump(Out); abort(); } // Verify that the list of all archetypes matches what we would // derive from the generic params. if (!checkAllArchetypes(genericParams)) { Out << "Archetypes list in generic parameter list doesn't " "match what would have been derived\n"; decl->dump(Out); abort(); } // Step through the list of requirements in the generic type. auto requirements = genericTy->getRequirements(); // Skip over same-type requirements. auto skipUnrepresentedRequirements = [&]() { for (; !requirements.empty(); requirements = requirements.slice(1)) { bool done = false; switch (requirements.front().getKind()) { case RequirementKind::Conformance: // If the second type is a protocol type, we're done. if (requirements.front().getSecondType()->is()) done = true; break; case RequirementKind::SameType: // Skip the next same-type constraint. continue; case RequirementKind::WitnessMarker: done = true; break; } if (done) break; } }; skipUnrepresentedRequirements(); // Collect all of the generic parameter lists. SmallVector allGenericParamLists; for (auto gpList = genericParams; gpList; gpList = gpList->getOuterParameters()) { allGenericParamLists.push_back(gpList); } std::reverse(allGenericParamLists.begin(), allGenericParamLists.end()); // Helpers that diagnose failures when generic requirements mismatch. bool failed = false; auto noteFailure =[&]() { if (failed) return; Out << "Generic requirements don't match all archetypes\n"; decl->dump(Out); Out << "\nGeneric type: " << genericTy->getString() << "\n"; Out << "Expected requirements: "; bool first = true; for (auto gpList : allGenericParamLists) { for (auto archetype : gpList->getAllArchetypes()) { for (auto proto : archetype->getConformsTo()) { if (first) first = false; else Out << ", "; Out << archetype->getString() << " : " << proto->getDeclaredType()->getString(); } } } Out << "\n"; failed = true; }; // Walk through all of the archetypes in the generic parameter lists, // matching up their conformance requirements with those in the for (auto gpList : allGenericParamLists) { for (auto archetype : gpList->getAllArchetypes()) { // Make sure we have the value witness marker. if (requirements.empty()) { noteFailure(); Out << "Ran out of requirements before we ran out of archetypes\n"; break; } if (requirements.front().getKind() == RequirementKind::WitnessMarker) { auto type = ArchetypeBuilder::mapTypeIntoContext( dc, requirements.front().getFirstType()); if (type->isEqual(archetype)) { requirements = requirements.slice(1); skipUnrepresentedRequirements(); } else { noteFailure(); Out << "Value witness marker for " << type->getString() << " does not match expected " << archetype->getString() << "\n"; } } else { noteFailure(); Out << "Missing value witness marker for " << archetype->getString() << "\n"; } for (auto proto : archetype->getConformsTo()) { // If there are no requirements left, we're missing requirements. if (requirements.empty()) { noteFailure(); Out << "No requirement for " << archetype->getString() << " : " << proto->getDeclaredType()->getString() << "\n"; continue; } auto firstReqType = ArchetypeBuilder::mapTypeIntoContext( dc, requirements.front().getFirstType()); auto secondReqType = ArchetypeBuilder::mapTypeIntoContext( dc, requirements.front().getSecondType()); // If the requirements match up, move on to the next requirement. if (firstReqType->isEqual(archetype) && secondReqType->isEqual(proto->getDeclaredType())) { requirements = requirements.slice(1); skipUnrepresentedRequirements(); continue; } noteFailure(); // If the requirements don't match up, complain. if (!firstReqType->isEqual(archetype)) { Out << "Mapped archetype " << firstReqType->getString() << " does not match expected " << archetype->getString() << "\n"; continue; } Out << "Mapped conformance " << secondReqType->getString() << " does not match expected " << proto->getDeclaredType()->getString() << "\n"; } } } if (!requirements.empty()) { noteFailure(); Out << "Extra requirement " << requirements.front().getFirstType()->getString() << " : " << requirements.front().getSecondType()->getString() << "\n"; } if (failed) abort(); } void verifyChecked(AbstractFunctionDecl *AFD) { PrettyStackTraceDecl debugStack("verifying AbstractFunctionDecl", AFD); // If this function is generic or is within a generic type, it should // have an interface type. if ((AFD->getGenericParams() || (AFD->getDeclContext()->isTypeContext() && AFD->getDeclContext()->getGenericParamsOfContext())) && !AFD->getInterfaceType()->is()) { Out << "Missing interface type for generic function\n"; AFD->dump(Out); abort(); } // If there is an interface type, it shouldn't have any unresolved // dependent member types. // FIXME: This is a general property of the type system. auto interfaceTy = AFD->getInterfaceType(); Type unresolvedDependentTy; interfaceTy.findIf([&](Type type) -> bool { if (auto dependent = type->getAs()) { if (dependent->getAssocType() == nullptr) { unresolvedDependentTy = dependent; return true; } } return false; }); if (unresolvedDependentTy) { Out << "Unresolved dependent member type "; unresolvedDependentTy->print(Out); abort(); } // If the interface type is generic, make sure its requirements // line up with the archetypes. if (auto genericTy = interfaceTy->getAs()) { checkGenericRequirements(AFD, AFD, genericTy); } verifyCheckedBase(AFD); } void verifyChecked(DestructorDecl *DD) { PrettyStackTraceDecl debugStack("verifying DestructorDecl", DD); auto *ND = DD->getExtensionType()->getNominalOrBoundGenericNominal(); if (!isa(ND) && !DD->isInvalid()) { Out << "DestructorDecls outside classes should be marked invalid"; abort(); } verifyCheckedBase(DD); } void verifyChecked(FuncDecl *FD) { verifyCheckedBase(FD); } void verifyParsed(FuncDecl *FD) { PrettyStackTraceDecl debugStack("verifying FuncDecl", FD); unsigned MinParamPatterns = FD->getImplicitSelfDecl() ? 2 : 1; if (FD->getBodyParamPatterns().size() < MinParamPatterns) { Out << "should have at least " << MinParamPatterns << " parameter patterns"; abort(); } if (FD->isAccessor()) { unsigned NumExpectedParamPatterns = 1; if (FD->getImplicitSelfDecl()) NumExpectedParamPatterns++; if (FD->getBodyParamPatterns().size() != NumExpectedParamPatterns) { Out << "accessors should not be curried"; abort(); } } if (auto *VD = FD->getAccessorStorageDecl()) { if (isa(VD) && cast(VD)->isStatic() != FD->isStatic()) { Out << "getter or setter static-ness must match static-ness of var"; abort(); } } verifyParsedBase(FD); } void verifyChecked(ClassDecl *CD) { PrettyStackTraceDecl debugStack("verifying ClassDecl", CD); if (!CD->hasLazyMembers()) { unsigned NumDestructors = 0; for (auto Member : CD->getMembers()) { if (isa(Member)) { NumDestructors++; } } if (NumDestructors != 1) { Out << "every class should have exactly one destructor, " "explicitly provided or created by the type checker"; abort(); } } if (!CD->hasDestructor()) { Out << "every class's 'has destructor' bit must be set"; abort(); } verifyCheckedBase(CD); } void verifyParsed(AssociatedTypeDecl *ATD) { PrettyStackTraceDecl debugStack("verifying AssociatedTypeDecl", ATD); auto *DC = ATD->getDeclContext(); if (!isa(DC) || !isa(cast(DC))) { Out << "AssociatedTypeDecl should only occur inside a protocol"; abort(); } verifyParsedBase(ATD); } void verifyParsed(TuplePattern *TP) { PrettyStackTracePattern debugStack(Ctx, "verifying TuplePattern", TP); if (TP->hasVararg()) { auto *LastPattern = TP->getFields().back().getPattern(); if (!isa(LastPattern)) { Out << "a vararg subpattern of a TuplePattern should be" "a TypedPattern"; abort(); } } verifyParsedBase(TP); } void verifyChecked(TuplePattern *TP) { PrettyStackTracePattern debugStack(Ctx, "verifying TuplePattern", TP); if (TP->hasVararg()) { auto *LastPattern = TP->getFields().back().getPattern(); Type T = cast(LastPattern)->getType()->getCanonicalType(); if (auto *BGT = T->getAs()) { if (BGT->getDecl() == Ctx.getArrayDecl()) return; } Out << "a vararg subpattern of a TuplePattern has wrong type"; abort(); } verifyCheckedBase(TP); } /// Look through a possible l-value type, returning true if it was /// an l-value. bool lookThroughLValue(Type &type, bool &isInOut) { if (LValueType *lv = type->getAs()) { Type objectType = lv->getObjectType(); if (objectType->is()) { Out << "type is an lvalue of lvalue type: "; type.print(Out); Out << "\n"; } isInOut = false; type = objectType; return true; } if (InOutType *io = type->getAs()) { Type objectType = io->getObjectType(); if (objectType->is()) { Out << "type is an inout of inout type: "; type.print(Out); Out << "\n"; } isInOut = true; type = objectType; return true; } return false; } /// The two types are required to either both be l-values or /// both not be l-values. They are adjusted to not be l-values. /// Returns true if they are both l-values. bool checkSameLValueness(Type &T0, Type &T1, const char *what) { bool Q0, Q1; bool isLValue0 = lookThroughLValue(T0, Q0); bool isLValue1 = lookThroughLValue(T1, Q1); if (isLValue0 != isLValue1) { Out << "lvalue-ness of " << what << " do not match: " << isLValue0 << ", " << isLValue1 << "\n"; abort(); } if (isLValue0 && Q0 != Q1) { Out << "qualification of " << what << " do not match\n"; abort(); } return isLValue0; } Type checkLValue(Type T, const char *what) { LValueType *LV = T->getAs(); if (LV) return LV->getObjectType(); Out << "type is not an l-value in " << what << ": "; T.print(Out); Out << "\n"; abort(); } // Verification utilities. Type checkMetatypeType(Type type, const char *what) { auto metatype = type->getAs(); if (metatype) return metatype->getInstanceType(); Out << what << " is not a metatype: "; type.print(Out); Out << "\n"; abort(); } void checkIsTypeOfRValue(ValueDecl *D, Type rvalueType, const char *what) { auto declType = D->getType(); if (auto refType = declType->getAs()) declType = refType->getReferentType(); checkSameType(declType, rvalueType, what); } void checkSameType(Type T0, Type T1, const char *what) { if (T0->getCanonicalType() == T1->getCanonicalType()) return; Out << "different types for " << what << ": "; T0.print(Out); Out << " vs. "; T1.print(Out); Out << "\n"; abort(); } void checkTrivialSubtype(Type srcTy, Type destTy, const char *what) { if (srcTy->isEqual(destTy)) return; if (auto srcMetatype = srcTy->getAs()) { if (auto destMetatype = destTy->getAs()) { return checkTrivialSubtype(srcMetatype->getInstanceType(), destMetatype->getInstanceType(), what); } goto fail; } // If the destination is a class, walk the supertypes of the source. if (destTy->getClassOrBoundGenericClass()) { if (!destTy->isSuperclassOf(srcTy, nullptr)) { srcTy.print(Out); Out << " is not a superclass of "; destTy.print(Out); Out << " for " << what << "\n"; abort(); } return; } // FIXME: Tighten up checking for conversions to protocol types. if (destTy->isExistentialType()) return; fail: Out << "subtype conversion in " << what << " is invalid: "; srcTy.print(Out); Out << " to "; destTy.print(Out); Out << "\n"; abort(); } void checkSameOrSubType(Type T0, Type T1, const char *what) { if (T0->getCanonicalType() == T1->getCanonicalType()) return; // Protocol subtyping. if (auto Proto0 = T0->getAs()) if (auto Proto1 = T1->getAs()) if (Proto0->getDecl()->inheritsFrom(Proto1->getDecl())) return; // FIXME: Actually check this? if (T0->isExistentialType() || T1->isExistentialType()) return; Out << "incompatible types for " << what << ": "; T0.print(Out); Out << " vs. "; T1.print(Out); Out << "\n"; abort(); } void checkMangling(ValueDecl *D) { llvm::SmallString<32> Buf; llvm::raw_svector_ostream OS(Buf); Mangle::Mangler Mangler(OS); Mangler.mangleDeclName(D); if (OS.str().empty()) { Out << "Mangler gave empty string for a ValueDecl"; abort(); } } bool isGoodSourceRange(SourceRange SR) { if (SR.isInvalid()) return false; (void) Ctx.SourceMgr.findBufferContainingLoc(SR.Start); (void) Ctx.SourceMgr.findBufferContainingLoc(SR.End); return true; } void checkSourceRanges(Expr *E) { PrettyStackTraceExpr debugStack(Ctx, "verifying ranges", E); if (!E->getSourceRange().isValid()) { // We don't care about source ranges on implicitly-generated // expressions. if (E->isImplicit()) return; Out << "invalid source range for expression: "; E->print(Out); Out << "\n"; abort(); } if (!isGoodSourceRange(E->getSourceRange())) { Out << "bad source range for expression: "; E->print(Out); Out << "\n"; abort(); } // FIXME: Re-visit this to always do the check. if (!E->isImplicit()) checkSourceRanges(E->getSourceRange(), Parent, [&]{ E->print(Out); } ); } void checkSourceRanges(Stmt *S) { PrettyStackTraceStmt debugStack(Ctx, "verifying ranges", S); if (!S->getSourceRange().isValid()) { // We don't care about source ranges on implicitly-generated // statements. if (S->isImplicit()) return; Out << "invalid source range for statement: "; S->print(Out); Out << "\n"; abort(); } if (!isGoodSourceRange(S->getSourceRange())) { Out << "bad source range for statement: "; S->print(Out); Out << "\n"; abort(); } checkSourceRanges(S->getSourceRange(), Parent, [&]{ S->print(Out); }); } void checkSourceRanges(Pattern *P) { PrettyStackTracePattern debugStack(Ctx, "verifying ranges", P); if (!P->getSourceRange().isValid()) { // We don't care about source ranges on implicitly-generated // patterns. if (P->isImplicit()) return; Out << "invalid source range for pattern: "; P->print(Out); Out << "\n"; abort(); } if (!isGoodSourceRange(P->getSourceRange())) { Out << "bad source range for pattern: "; P->print(Out); Out << "\n"; abort(); } checkSourceRanges(P->getSourceRange(), Parent, [&]{ P->print(Out); }); } void checkSourceRanges(Decl *D) { PrettyStackTraceDecl debugStack("verifying ranges", D); if (!D->getSourceRange().isValid()) { // We don't care about source ranges on implicitly-generated // decls. if (D->isImplicit()) return; Out << "invalid source range for decl: "; D->print(Out); Out << "\n"; abort(); } checkSourceRanges(D->getSourceRange(), Parent, [&]{ D->print(Out); }); if (auto *VD = dyn_cast(D)) { if (!VD->getTypeSourceRangeForDiagnostics().isValid()) { Out << "invalid type source range for variable decl: "; D->print(Out); Out << "\n"; abort(); } } } /// \brief Verify that the given source ranges is contained within the /// parent's source range. void checkSourceRanges(SourceRange Current, ASTWalker::ParentTy Parent, std::function printEntity) { SourceRange Enclosing; if (Parent.isNull()) return; if (Parent.getAsModule()) { return; } else if (Decl *D = Parent.getAsDecl()) { Enclosing = D->getSourceRange(); if (D->isImplicit()) return; // FIXME: This is not working well for decl parents. return; } else if (Stmt *S = Parent.getAsStmt()) { Enclosing = S->getSourceRange(); if (S->isImplicit()) return; } else if (Pattern *P = Parent.getAsPattern()) { Enclosing = P->getSourceRange(); } else if (Expr *E = Parent.getAsExpr()) { // FIXME: This hack is required because the inclusion check below // doesn't compares the *start* of the ranges, not the end of the // ranges. In the case of an interpolated string literal expr, the // subexpressions are contained within the string token. This means // that comparing the start of the string token to the end of an // embedded expression will fail. if (isa(E)) return; if (E->isImplicit()) return; Enclosing = E->getSourceRange(); } else if (TypeRepr *TyR = Parent.getAsTypeRepr()) { Enclosing = TyR->getSourceRange(); } else { llvm_unreachable("impossible parent node"); } if (!Ctx.SourceMgr.rangeContains(Enclosing, Current)) { Out << "child source range not contained within its parent: "; printEntity(); Out << "\n parent range: "; Enclosing.print(Out, Ctx.SourceMgr); Out << "\n child range: "; Current.print(Out, Ctx.SourceMgr); Out << "\n"; abort(); } } void checkErrors(Expr *E) {} void checkErrors(Stmt *S) {} void checkErrors(Pattern *P) {} void checkErrors(Decl *D) {} void checkErrors(ValueDecl *D) { PrettyStackTraceDecl debugStack("verifying errors", D); if (!D->hasType()) return; if (D->isInvalid() && !D->getType()->is()) { Out << "Invalid decl has non-error type!\n"; D->dump(Out); abort(); } if (D->getType()->is() && !D->isInvalid()) { Out << "Valid decl has error type!\n"; D->dump(Out); abort(); } } }; } void swift::verify(SourceFile &SF) { Verifier verifier(SF, &SF); SF.walk(verifier); } void swift::verify(Decl *D) { Verifier V = Verifier::forDecl(D); D->walk(V); }