/// Determine the relationship between the self types of the given declaration /// contexts.. static SelfTypeRelationship computeSelfTypeRelationship(TypeChecker &tc, DeclContext *dc, DeclContext *dc1, DeclContext *dc2){ // If at least one of the contexts is a non-type context, the two are // unrelated. if (!dc1->isTypeContext() || !dc2->isTypeContext()) return SelfTypeRelationship::Unrelated; Type type1 = dc1->getDeclaredInterfaceType(); Type type2 = dc2->getDeclaredInterfaceType(); // If the types are equal, the answer is simple. if (type1->isEqual(type2)) return SelfTypeRelationship::Equivalent; // If both types can have superclasses, which whether one is a superclass // of the other. The subclass is the common base type. if (type1->mayHaveSuperclass() && type2->mayHaveSuperclass()) { if (isNominallySuperclassOf(tc, type1, type2)) return SelfTypeRelationship::Superclass; if (isNominallySuperclassOf(tc, type2, type1)) return SelfTypeRelationship::Subclass; return SelfTypeRelationship::Unrelated; } // If neither or both are protocol types, consider the bases unrelated. bool isProtocol1 = isa<ProtocolDecl>(dc1); bool isProtocol2 = isa<ProtocolDecl>(dc2); if (isProtocol1 == isProtocol2) return SelfTypeRelationship::Unrelated; // Just one of the two is a protocol. Check whether the other conforms to // that protocol. Type protoTy = isProtocol1? type1 : type2; Type modelTy = isProtocol1? type2 : type1; auto proto = protoTy->castTo<ProtocolType>()->getDecl(); // If the model type does not conform to the protocol, the bases are // unrelated. if (!tc.conformsToProtocol(modelTy, proto, dc, ConformanceCheckFlags::InExpression)) return SelfTypeRelationship::Unrelated; return isProtocol1? SelfTypeRelationship::ConformedToBy : SelfTypeRelationship::ConformsTo; }
void ArraySetElementAST::typeCheck(TypeChecker& checker) { mArrayRefExpression->typeCheck(checker); mAccessExpression->typeCheck(checker); mRightHandSide->typeCheck(checker); //Check if array auto arrayRefType = std::dynamic_pointer_cast<ArrayType>(mArrayRefExpression->expressionType(checker)); if (arrayRefType == nullptr) { checker.typeError("The expression '" + mArrayRefExpression->asString() + "' is not of array type."); } //Access access checker.assertSameType( *checker.makeType("Int"), *mAccessExpression->expressionType(checker), "Expected the array indexing to be of type 'Int'."); //Check rhs checker.assertSameType( *arrayRefType->elementType(), *mRightHandSide->expressionType(checker), asString()); }
static Optional<Type> getTypeOfCompletionContextExpr( TypeChecker &TC, DeclContext *DC, CompletionTypeCheckKind kind, Expr *&parsedExpr, ConcreteDeclRef &referencedDecl) { switch (kind) { case CompletionTypeCheckKind::Normal: // Handle below. break; case CompletionTypeCheckKind::ObjCKeyPath: referencedDecl = nullptr; if (auto keyPath = dyn_cast<ObjCKeyPathExpr>(parsedExpr)) return TC.checkObjCKeyPathExpr(DC, keyPath, /*requireResultType=*/true); return None; } Type originalType = parsedExpr->getType(); if (auto T = TC.getTypeOfExpressionWithoutApplying(parsedExpr, DC, referencedDecl, FreeTypeVariableBinding::GenericParameters)) return T; // Try to recover if we've made any progress. if (parsedExpr && !isa<ErrorExpr>(parsedExpr) && parsedExpr->getType() && !parsedExpr->getType()->hasError() && (originalType.isNull() || !parsedExpr->getType()->isEqual(originalType))) { return parsedExpr->getType(); } return None; }
ValuePtr BSequence::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { for(auto& e : args) { TypeSubst lastSubst; checker.subst.swap(lastSubst); checker.Visit(e.get()); if(!e->value) return {}; Compose(lastSubst, checker.subst); } return args.back()->value; }
/// getInfixData - If the specified expression is an infix binary /// operator, return its infix operator attributes. static InfixData getInfixData(TypeChecker &TC, DeclContext *DC, Expr *E) { if (auto *ifExpr = dyn_cast<IfExpr>(E)) { // Ternary has fixed precedence. assert(!ifExpr->isFolded() && "already folded if expr in sequence?!"); (void)ifExpr; return InfixData(IntrinsicPrecedences::IfExpr, Associativity::Right, /*assignment*/ false); } else if (auto *assign = dyn_cast<AssignExpr>(E)) { // Assignment has fixed precedence. assert(!assign->isFolded() && "already folded assign expr in sequence?!"); (void)assign; return InfixData(IntrinsicPrecedences::AssignExpr, Associativity::Right, /*assignment*/ true); } else if (auto *as = dyn_cast<ExplicitCastExpr>(E)) { // 'as' and 'is' casts have fixed precedence. assert(!as->isFolded() && "already folded 'as' expr in sequence?!"); (void)as; return InfixData(IntrinsicPrecedences::ExplicitCastExpr, Associativity::None, /*assignment*/ false); } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { SourceFile *SF = DC->getParentSourceFile(); Identifier name = DRE->getDecl()->getName(); bool isCascading = DC->isCascadingContextForLookup(true); if (InfixOperatorDecl *op = SF->lookupInfixOperator(name, isCascading, E->getLoc())) return op->getInfixData(); } else if (OverloadedDeclRefExpr *OO = dyn_cast<OverloadedDeclRefExpr>(E)) { SourceFile *SF = DC->getParentSourceFile(); Identifier name = OO->getDecls()[0]->getName(); bool isCascading = DC->isCascadingContextForLookup(true); if (InfixOperatorDecl *op = SF->lookupInfixOperator(name, isCascading, E->getLoc())) return op->getInfixData(); } TC.diagnose(E->getLoc(), diag::unknown_binop); // Recover with an infinite-precedence left-associative operator. return InfixData((unsigned char)~0U, Associativity::Left, /*assignment*/ false); }
/// Check the generic parameters in the given generic parameter list (and its /// parent generic parameter lists) according to the given resolver. void checkGenericParamList(TypeChecker &tc, GenericSignatureBuilder *builder, GenericParamList *genericParams, GenericSignature *parentSig, TypeResolution resolution) { // If there is a parent context, add the generic parameters and requirements // from that context. if (builder) builder->addGenericSignature(parentSig); // If there aren't any generic parameters at this level, we're done. if (!genericParams) return; assert(genericParams->size() > 0 && "Parsed an empty generic parameter list?"); // Determine where and how to perform name lookup. TypeResolutionOptions options = None; DeclContext *lookupDC = genericParams->begin()[0]->getDeclContext(); assert(lookupDC == resolution.getDeclContext()); // First, add the generic parameters to the generic signature builder. // Do this before checking the inheritance clause, since it may // itself be dependent on one of these parameters. if (builder) { for (auto param : *genericParams) builder->addGenericParameter(param); } // Add the requirements for each of the generic parameters to the builder. // Now, check the inheritance clauses of each parameter. if (builder) { for (auto param : *genericParams) builder->addGenericParameterRequirements(param); } // Add the requirements clause to the builder, validating the types in // the requirements clause along the way. tc.validateRequirements(genericParams->getWhereLoc(), genericParams->getRequirements(), resolution, options, builder); }
static Type getResultType(TypeChecker &TC, FuncDecl *fn, Type resultType) { // Look through optional types. OptionalTypeKind optKind; if (auto origValueType = resultType->getAnyOptionalObjectType(optKind)) { // Get the interface type of the result. Type ifaceValueType = getResultType(TC, fn, origValueType); // Preserve the optional type's original spelling if the interface // type is the same as the original. if (origValueType.getPointer() == ifaceValueType.getPointer()) { return resultType; } // Wrap the interface type in the right kind of optional. switch (optKind) { case OTK_None: llvm_unreachable("impossible"); case OTK_Optional: return OptionalType::get(ifaceValueType); case OTK_ImplicitlyUnwrappedOptional: return ImplicitlyUnwrappedOptionalType::get(ifaceValueType); } llvm_unreachable("bad optional kind"); } // Rewrite dynamic self to the appropriate interface type. if (resultType->is<DynamicSelfType>()) { return fn->getDynamicSelfInterface(); } // Weird hacky special case. if (!fn->getBodyResultTypeLoc().hasLocation() && fn->isGenericContext()) { // FIXME: This should not be rewritten. This is only needed in cases where // we synthesize a function which returns a generic value. In that case, // the return type is specified in terms of archetypes, but has no TypeLoc // in the TypeRepr. Because of this, Sema isn't able to rebuild it in // terms of interface types. When interface types prevail, this should be // removed. Until then, we hack the mapping here. return TC.getInterfaceTypeFromInternalType(fn, resultType); } return resultType; }
ValuePtr BReturn::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { assert(args.size() == 0 || args.size() == 1); TypePtr rty = VoidType; if(!args.empty()) { checker.Visit(args[0].get()); if(!args[0]->value) return {}; rty = args[0]->value->type; } if(checker.returnType) Compose(Unify(*rty, *checker.returnType), checker.subst); else checker.returnType = rty; return VoidValue; }
/// Returns whether the given type conforms to the given {En,De}codable /// protocol. /// /// \param tc The typechecker to use in validating {En,De}codable conformance. /// /// \param context The \c DeclContext the var declarations belong to. /// /// \param target The \c Type to validate. /// /// \param proto The \c ProtocolDecl to check conformance to. static CodableConformanceType typeConformsToCodable(TypeChecker &tc, DeclContext *context, Type target, ProtocolDecl *proto) { // Some generic types need to be introspected to get at their "true" Codable // conformance. auto canType = target->getCanonicalType(); if (auto genericType = dyn_cast<BoundGenericType>(canType)) { auto *nominalTypeDecl = genericType->getAnyNominal(); // Implicitly unwrapped optionals need to be unwrapped; // ImplicitlyUnwrappedOptional does not need to conform to Codable directly // -- only its inner type does. if (nominalTypeDecl == tc.Context.getImplicitlyUnwrappedOptionalDecl() || // FIXME: Remove the following when conditional conformance lands. // Some generic types in the stdlib currently conform to Codable even // when the type they are generic on does not [Optional, Array, Set, // Dictionary]. For synthesizing conformance, we don't want to // consider these types as Codable if the nested type is not Codable. // Look through the generic type parameters of these types recursively // to avoid synthesizing code that will crash at runtime. // // We only want to look through generic params for these types; other // types may validly conform to Codable even if their generic param // types do not. nominalTypeDecl == tc.Context.getOptionalDecl() || nominalTypeDecl == tc.Context.getArrayDecl() || nominalTypeDecl == tc.Context.getSetDecl() || nominalTypeDecl == tc.Context.getDictionaryDecl()) { for (auto paramType : genericType->getGenericArgs()) { if (typeConformsToCodable(tc, context, paramType, proto) != Conforms) return DoesNotConform; } return Conforms; } } return tc.conformsToProtocol(target, proto, context, ConformanceCheckFlags::Used) ? Conforms : DoesNotConform; }
void SetFieldValueAST::typeCheck(TypeChecker& checker) { mObjectRefExpression->typeCheck(checker); std::shared_ptr<Type> objRefType; if (auto varRef = std::dynamic_pointer_cast<VariableReferenceExpressionAST>(mObjectRefExpression)) { auto varSymbol = std::dynamic_pointer_cast<VariableSymbol>(mSymbolTable->find(varRef->name())); objRefType = checker.findType(varSymbol->variableType()); } else if (auto arrayRef = std::dynamic_pointer_cast<ArrayAccessAST>(mObjectRefExpression)) { objRefType = arrayRef->expressionType(checker); } else { checker.typeError("Not implemented"); } auto memberName = getMemberName(); std::string objName = objRefType->name(); if (!checker.objectExists(objName)) { checker.typeError(objRefType->name() + " is not an object type."); } auto& object = checker.getObject(objName); if (!object.fieldExists(memberName)) { checker.typeError("There exists no field '" + memberName + "' in the type '" + objRefType->name() + "'."); } mRightHandSide->typeCheck(checker); //Check rhs std::shared_ptr<Type> fieldType; if (std::dynamic_pointer_cast<ArrayAccessAST>(mMemberExpression)) { fieldType = std::dynamic_pointer_cast<ArrayType>(object.getField(memberName).type())->elementType(); } else { fieldType = object.getField(memberName).type(); } checker.assertSameType( *fieldType, *mRightHandSide->expressionType(checker), asString()); }
/// Returns whether the given type conforms to the given {En,De}codable /// protocol. /// /// \param tc The typechecker to use in validating {En,De}codable conformance. /// /// \param context The \c DeclContext the var declarations belong to. /// /// \param target The \c Type to validate. /// /// \param proto The \c ProtocolDecl to check conformance to. static CodableConformanceType typeConformsToCodable(TypeChecker &tc, DeclContext *context, Type target, bool isIUO, ProtocolDecl *proto) { target = context->mapTypeIntoContext(target->mapTypeOutOfContext()); // Some generic types need to be introspected to get at their "true" Codable // conformance. if (auto referenceType = target->getAs<ReferenceStorageType>()) { // This is a weak/unowned/unmanaged var. Get the inner type before checking // conformance. target = referenceType->getReferentType(); } if (isIUO) return typeConformsToCodable(tc, context, target->getOptionalObjectType(), false, proto); return tc.conformsToProtocol(target, proto, context, ConformanceCheckFlags::Used) ? Conforms : DoesNotConform; }
void ArrayDeclarationAST::typeCheck(TypeChecker& checker) { mLengthExpression->typeCheck(checker); //Check length checker.assertSameType( *checker.makeType("Int"), *mLengthExpression->expressionType(checker), "Expected the length to be of type 'Int'."); //Check if the element type exists checker.assertTypeExists(elementType(), false); checker.assertNotVoid(*checker.findType(elementType()), "Arrays of type 'Void' is not allowed."); //Create the array type if not created checker.makeType(elementType() + "[]"); }
Type DerivedConformance::deriveRawRepresentable(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *type, AssociatedTypeDecl *assocType) { // We can only synthesize RawRepresentable for enums. auto enumDecl = dyn_cast<EnumDecl>(type); if (!enumDecl) return nullptr; // Check other preconditions for synthesized conformance. if (!canSynthesizeRawRepresentable(tc, parentDecl, enumDecl)) return nullptr; if (assocType->getName() == tc.Context.Id_RawValue) { return deriveRawRepresentable_Raw(tc, parentDecl, enumDecl); } tc.diagnose(assocType->getLoc(), diag::broken_raw_representable_requirement); return nullptr; }
// For a generic requirement in a protocol, make sure that the requirement // set didn't add any requirements to Self or its associated types. static bool checkProtocolSelfRequirements(GenericSignature *sig, ValueDecl *decl, TypeChecker &TC) { // For a generic requirement in a protocol, make sure that the requirement // set didn't add any requirements to Self or its associated types. if (auto *proto = dyn_cast<ProtocolDecl>(decl->getDeclContext())) { auto protoSelf = proto->getSelfInterfaceType(); for (auto req : sig->getRequirements()) { // If one of the types in the requirement is dependent on a non-Self // type parameter, this requirement is okay. if (!isSelfDerivedOrConcrete(protoSelf, req.getFirstType()) || !isSelfDerivedOrConcrete(protoSelf, req.getSecondType())) continue; // The conformance of 'Self' to the protocol is okay. if (req.getKind() == RequirementKind::Conformance && req.getSecondType()->getAs<ProtocolType>()->getDecl() == proto && req.getFirstType()->is<GenericTypeParamType>()) continue; TC.diagnose(decl, TC.Context.LangOpts.EffectiveLanguageVersion[0] >= 4 ? diag::requirement_restricts_self : diag::requirement_restricts_self_swift3, decl->getDescriptiveKind(), decl->getFullName(), req.getFirstType().getString(), static_cast<unsigned>(req.getKind()), req.getSecondType().getString()); if (TC.Context.LangOpts.EffectiveLanguageVersion[0] >= 4) return true; } } return false; }
void MultiDimArrayDeclarationAST::typeCheck(TypeChecker& checker) { for (auto lengthExpr : mLengthExpressions) { lengthExpr->typeCheck(checker); } //Check lengths int dim = 0; for (auto lengthExpr : mLengthExpressions) { checker.assertSameType( *checker.makeType("Int"), *lengthExpr->expressionType(checker), "Expected the length of dimension " + std::to_string(dim) + " to be of type 'Int'."); dim++; } //Check if the element type exists checker.assertTypeExists(elementType(), false); checker.assertNotVoid(*checker.findType(elementType()), "Arrays of type 'Void' is not allowed."); //Create all array types for (int i = 0; i < mLengthExpressions.size(); i++) { checker.makeType(typeString(i)); } }
/// All generic parameters of a generic function must be referenced in the /// declaration's type, otherwise we have no way to infer them. static void checkReferencedGenericParams(GenericContext *dc, GenericSignature *sig, TypeChecker &TC) { auto *genericParams = dc->getGenericParams(); if (!genericParams) return; auto *decl = cast<ValueDecl>(dc->getInnermostDeclarationDeclContext()); // A helper class to collect referenced generic type parameters // and dependent member types. class ReferencedGenericTypeWalker : public TypeWalker { SmallPtrSet<CanType, 4> ReferencedGenericParams; public: ReferencedGenericTypeWalker() {} Action walkToTypePre(Type ty) override { // Find generic parameters or dependent member types. // Once such a type is found, don't recurse into its children. if (!ty->hasTypeParameter()) return Action::SkipChildren; if (ty->isTypeParameter()) { ReferencedGenericParams.insert(ty->getCanonicalType()); return Action::SkipChildren; } return Action::Continue; } SmallPtrSet<CanType, 4> &getReferencedGenericParams() { return ReferencedGenericParams; } }; // Collect all generic params referenced in parameter types and // return type. ReferencedGenericTypeWalker paramsAndResultWalker; auto *funcTy = decl->getInterfaceType()->castTo<GenericFunctionType>(); funcTy->getInput().walk(paramsAndResultWalker); funcTy->getResult().walk(paramsAndResultWalker); // Set of generic params referenced in parameter types, // return type or requirements. auto &referencedGenericParams = paramsAndResultWalker.getReferencedGenericParams(); // Check if at least one of the generic params in the requirement refers // to an already referenced generic parameter. If this is the case, // then the other type is also considered as referenced, because // it is used to put requirements on the first type. auto reqTypesVisitor = [&referencedGenericParams](Requirement req) -> bool { Type first; Type second; switch (req.getKind()) { case RequirementKind::Superclass: case RequirementKind::SameType: second = req.getSecondType(); LLVM_FALLTHROUGH; case RequirementKind::Conformance: case RequirementKind::Layout: first = req.getFirstType(); break; } // Collect generic parameter types referenced by types used in a requirement. ReferencedGenericTypeWalker walker; if (first && first->hasTypeParameter()) first.walk(walker); if (second && second->hasTypeParameter()) second.walk(walker); auto &genericParamsUsedByRequirementTypes = walker.getReferencedGenericParams(); // If at least one of the collected generic types or a root generic // parameter of dependent member types is known to be referenced by // parameter types, return types or other types known to be "referenced", // then all the types used in the requirement are considered to be // referenced, because they are used to defined something that is known // to be referenced. bool foundNewReferencedGenericParam = false; if (std::any_of(genericParamsUsedByRequirementTypes.begin(), genericParamsUsedByRequirementTypes.end(), [&referencedGenericParams](CanType t) { assert(t->isTypeParameter()); return referencedGenericParams.find( t->getRootGenericParam() ->getCanonicalType()) != referencedGenericParams.end(); })) { std::for_each(genericParamsUsedByRequirementTypes.begin(), genericParamsUsedByRequirementTypes.end(), [&referencedGenericParams, &foundNewReferencedGenericParam](CanType t) { // Add only generic type parameters, but ignore any // dependent member types, because requirement // on a dependent member type does not provide enough // information to infer the base generic type // parameter. if (!t->is<GenericTypeParamType>()) return; if (referencedGenericParams.insert(t).second) foundNewReferencedGenericParam = true; }); } return foundNewReferencedGenericParam; }; ArrayRef<Requirement> requirements; auto FindReferencedGenericParamsInRequirements = [&requirements, sig, &reqTypesVisitor] { requirements = sig->getRequirements(); // Try to find new referenced generic parameter types in requirements until // we reach a fix point. We need to iterate until a fix point, because we // may have e.g. chains of same-type requirements like: // not-yet-referenced-T1 == not-yet-referenced-T2.DepType2, // not-yet-referenced-T2 == not-yet-referenced-T3.DepType3, // not-yet-referenced-T3 == referenced-T4.DepType4. // When we process the first of these requirements, we don't know yet that // T2 // will be referenced, because T3 will be referenced, // because T3 == T4.DepType4. while (true) { bool foundNewReferencedGenericParam = false; for (auto req : requirements) { if (reqTypesVisitor(req)) foundNewReferencedGenericParam = true; } if (!foundNewReferencedGenericParam) break; } }; // Find the depth of the function's own generic parameters. unsigned fnGenericParamsDepth = genericParams->getDepth(); // Check that every generic parameter type from the signature is // among referencedGenericParams. for (auto *genParam : sig->getGenericParams()) { auto *paramDecl = genParam->getDecl(); if (paramDecl->getDepth() != fnGenericParamsDepth) continue; if (!referencedGenericParams.count(genParam->getCanonicalType())) { // Lazily search for generic params that are indirectly used in the // function signature. Do it only if there is a generic parameter // that is not known to be referenced yet. if (requirements.empty()) { FindReferencedGenericParamsInRequirements(); // Nothing to do if this generic parameter is considered to be // referenced after analyzing the requirements from the generic // signature. if (referencedGenericParams.count(genParam->getCanonicalType())) continue; } // Produce an error that this generic parameter cannot be bound. TC.diagnose(paramDecl->getLoc(), diag::unreferenced_generic_parameter, paramDecl->getNameStr()); decl->setInterfaceType(ErrorType::get(TC.Context)); decl->setInvalid(); } } }
bool operator() (const operator_ * a) const { return !thea->typecheckAction(a); };
static void bindExtensionDecl(ExtensionDecl *ED, TypeChecker &TC) { if (ED->getExtendedType()) return; // If we didn't parse a type, fill in an error type and bail out. if (!ED->getExtendedTypeLoc().getTypeRepr()) { ED->setInvalid(); ED->getExtendedTypeLoc().setInvalidType(TC.Context); return; } auto dc = ED->getDeclContext(); // Validate the representation. // FIXME: Perform some kind of "shallow" validation here? TypeResolutionOptions options; options |= TR_AllowUnboundGenerics; options |= TR_ExtensionBinding; if (TC.validateType(ED->getExtendedTypeLoc(), dc, options)) { ED->setInvalid(); return; } // Dig out the extended type. auto extendedType = ED->getExtendedType(); // Hack to allow extending a generic typealias. if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) { if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) { auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); if (extendedNominal) { extendedType = extendedNominal->getDeclaredType(); ED->getExtendedTypeLoc().setType(extendedType); } } } // Handle easy cases. // Cannot extend a metatype. if (extendedType->is<AnyMetatypeType>()) { TC.diagnose(ED->getLoc(), diag::extension_metatype, extendedType) .highlight(ED->getExtendedTypeLoc().getSourceRange()); ED->setInvalid(); ED->getExtendedTypeLoc().setInvalidType(TC.Context); return; } // Cannot extend a bound generic type. if (extendedType->isSpecialized()) { TC.diagnose(ED->getLoc(), diag::extension_specialization, extendedType->getAnyNominal()->getName()) .highlight(ED->getExtendedTypeLoc().getSourceRange()); ED->setInvalid(); ED->getExtendedTypeLoc().setInvalidType(TC.Context); return; } // Dig out the nominal type being extended. NominalTypeDecl *extendedNominal = extendedType->getAnyNominal(); if (!extendedNominal) { TC.diagnose(ED->getLoc(), diag::non_nominal_extension, extendedType) .highlight(ED->getExtendedTypeLoc().getSourceRange()); ED->setInvalid(); ED->getExtendedTypeLoc().setInvalidType(TC.Context); return; } assert(extendedNominal && "Should have the nominal type being extended"); // If the extended type is generic or is a protocol. Clone or create // the generic parameters. if (extendedNominal->isGenericContext()) { if (auto proto = dyn_cast<ProtocolDecl>(extendedNominal)) { // For a protocol extension, build the generic parameter list. ED->setGenericParams(proto->createGenericParams(ED)); } else { // Clone the existing generic parameter list. ED->setGenericParams( cloneGenericParams(TC.Context, ED, extendedNominal->getGenericParamsOfContext())); } } // If we have a trailing where clause, deal with it now. // For now, trailing where clauses are only permitted on protocol extensions. if (auto trailingWhereClause = ED->getTrailingWhereClause()) { if (!extendedNominal->isGenericContext()) { // Only generic and protocol types are permitted to have // trailing where clauses. TC.diagnose(ED, diag::extension_nongeneric_trailing_where, extendedType) .highlight(trailingWhereClause->getSourceRange()); ED->setTrailingWhereClause(nullptr); } else { // Merge the trailing where clause into the generic parameter list. // FIXME: Long-term, we'd like clients to deal with the trailing where // clause explicitly, but for now it's far more direct to represent // the trailing where clause as part of the requirements. ED->getGenericParams()->addTrailingWhereClause( TC.Context, trailingWhereClause->getWhereLoc(), trailingWhereClause->getRequirements()); } } extendedNominal->addExtension(ED); }
/// Validates the given CodingKeys enum decl by ensuring its cases are a 1-to-1 /// match with the stored vars of the given type. /// /// \param tc The typechecker to use in validating {En,De}codable conformance. /// /// \param codingKeysDecl The \c CodingKeys enum decl to validate. /// /// \param target The nominal type decl to validate the \c CodingKeys against. /// /// \param proto The {En,De}codable protocol to validate all the keys conform /// to. static bool validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl, NominalTypeDecl *target, ProtocolDecl *proto) { // Look through all var decls in the given type. // * Filter out lazy/computed vars (currently already done by // getStoredProperties). // * Filter out ones which are present in the given decl (by name). // // If any of the entries in the CodingKeys decl are not present in the type // by name, then this decl doesn't match. // If there are any vars left in the type which don't have a default value // (for Decodable), then this decl doesn't match. // Here we'll hold on to properties by name -- when we've validated a property // against its CodingKey entry, it will get removed. llvm::SmallDenseMap<Identifier, VarDecl *, 8> properties; for (auto *varDecl : target->getStoredProperties(/*skipInaccessible=*/true)) { properties[varDecl->getName()] = varDecl; } bool propertiesAreValid = true; for (auto elt : codingKeysDecl->getAllElements()) { auto it = properties.find(elt->getName()); if (it == properties.end()) { tc.diagnose(elt->getLoc(), diag::codable_extraneous_codingkey_case_here, elt->getName()); // TODO: Investigate typo-correction here; perhaps the case name was // misspelled and we can provide a fix-it. propertiesAreValid = false; continue; } // We have a property to map to. Ensure it's {En,De}codable. auto conformance = varConformsToCodable(tc, target->getDeclContext(), it->second, proto); switch (conformance) { case Conforms: // The property was valid. Remove it from the list. properties.erase(it); break; case DoesNotConform: tc.diagnose(it->second->getLoc(), diag::codable_non_conforming_property_here, proto->getDeclaredType(), it->second->getType()); LLVM_FALLTHROUGH; case TypeNotValidated: // We don't produce a diagnostic for a type which failed to validate. // This will produce a diagnostic elsewhere anyway. propertiesAreValid = false; continue; } } if (!propertiesAreValid) return false; // If there are any remaining properties which the CodingKeys did not cover, // we can skip them on encode. On decode, though, we can only skip them if // they have a default value. if (!properties.empty() && proto == tc.Context.getProtocol(KnownProtocolKind::Decodable)) { for (auto it = properties.begin(); it != properties.end(); ++it) { if (it->second->getParentInitializer() != nullptr) { // Var has a default value. continue; } propertiesAreValid = false; tc.diagnose(it->second->getLoc(), diag::codable_non_decoded_property_here, proto->getDeclaredType(), it->first); } } return propertiesAreValid; }
/// \brief Determine whether the first declaration is as "specialized" as /// the second declaration. /// /// "Specialized" is essentially a form of subtyping, defined below. static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2) { if (tc.getLangOpts().DebugConstraintSolver) { auto &log = tc.Context.TypeCheckerDebug->getStream(); log << "Comparing declarations\n"; decl1->print(log); log << "\nand\n"; decl2->print(log); log << "\n"; } if (!tc.specializedOverloadComparisonCache.count({decl1, decl2})) { auto compareSpecializations = [&] () -> bool { // If the kinds are different, there's nothing we can do. // FIXME: This is wrong for type declarations, which we're skipping // entirely. if (decl1->getKind() != decl2->getKind() || isa<TypeDecl>(decl1)) return false; // A non-generic declaration is more specialized than a generic declaration. if (auto func1 = dyn_cast<AbstractFunctionDecl>(decl1)) { auto func2 = cast<AbstractFunctionDecl>(decl2); if (static_cast<bool>(func1->getGenericParams()) != static_cast<bool>(func2->getGenericParams())) return func2->getGenericParams(); } // A witness is always more specialized than the requirement it satisfies. switch (compareWitnessAndRequirement(tc, dc, decl1, decl2)) { case Comparison::Unordered: break; case Comparison::Better: return true; case Comparison::Worse: return false; } // Members of protocol extensions have special overloading rules. ProtocolDecl *inProtocolExtension1 = decl1->getDeclContext() ->isProtocolExtensionContext(); ProtocolDecl *inProtocolExtension2 = decl2->getDeclContext() ->isProtocolExtensionContext(); if (inProtocolExtension1 && inProtocolExtension2) { // Both members are in protocol extensions. // Determine whether the 'Self' type from the first protocol extension // satisfies all of the requirements of the second protocol extension. DeclContext *dc1 = decl1->getDeclContext(); DeclContext *dc2 = decl2->getDeclContext(); bool better1 = isProtocolExtensionAsSpecializedAs(tc, dc1, dc2); bool better2 = isProtocolExtensionAsSpecializedAs(tc, dc2, dc1); if (better1 != better2) { return better1; } } else if (inProtocolExtension1 || inProtocolExtension2) { // One member is in a protocol extension, the other is in a concrete type. // Prefer the member in the concrete type. return inProtocolExtension2; } Type type1 = decl1->getInterfaceType(); Type type2 = decl2->getInterfaceType(); /// What part of the type should we check? enum { CheckAll, CheckInput, } checkKind; if (isa<AbstractFunctionDecl>(decl1) || isa<EnumElementDecl>(decl1)) { // Nothing to do: these have the curried 'self' already. if (auto elt = dyn_cast<EnumElementDecl>(decl1)) { checkKind = elt->hasArgumentType() ? CheckInput : CheckAll; } else { checkKind = CheckInput; } } else { // Add a curried 'self' type. assert(!type1->is<GenericFunctionType>() && "Odd generic function type?"); assert(!type2->is<GenericFunctionType>() && "Odd generic function type?"); type1 = addCurriedSelfType(tc.Context, type1, decl1->getDeclContext()); type2 = addCurriedSelfType(tc.Context, type2, decl2->getDeclContext()); // For a subscript declaration, only look at the input type (i.e., the // indices). if (isa<SubscriptDecl>(decl1)) checkKind = CheckInput; else checkKind = CheckAll; } // Construct a constraint system to compare the two declarations. ConstraintSystem cs(tc, dc, ConstraintSystemOptions()); auto locator = cs.getConstraintLocator(nullptr); // FIXME: Locator when anchored on a declaration. // Get the type of a reference to the second declaration. Type openedType2 = cs.openType(type2, locator, decl2->getInnermostDeclContext()); // Get the type of a reference to the first declaration, swapping in // archetypes for the dependent types. llvm::DenseMap<CanType, TypeVariableType *> replacements; auto dc1 = decl1->getInnermostDeclContext(); Type openedType1 = cs.openType(type1, locator, replacements, dc1); for (const auto &replacement : replacements) { if (auto mapped = ArchetypeBuilder::mapTypeIntoContext(dc1, replacement.first)) { cs.addConstraint(ConstraintKind::Bind, replacement.second, mapped, locator); } } // Extract the self types from the declarations, if they have them. Type selfTy1; Type selfTy2; if (decl1->getDeclContext()->isTypeContext()) { auto funcTy1 = openedType1->castTo<FunctionType>(); selfTy1 = funcTy1->getInput()->getRValueInstanceType(); openedType1 = funcTy1->getResult(); } if (decl2->getDeclContext()->isTypeContext()) { auto funcTy2 = openedType2->castTo<FunctionType>(); selfTy2 = funcTy2->getInput()->getRValueInstanceType(); openedType2 = funcTy2->getResult(); } // Determine the relationship between the 'self' types and add the // appropriate constraints. The constraints themselves never fail, but // they help deduce type variables that were opened. switch (computeSelfTypeRelationship(tc, dc, decl1->getDeclContext(), decl2->getDeclContext())) { case SelfTypeRelationship::Unrelated: // Skip the self types parameter entirely. break; case SelfTypeRelationship::Equivalent: cs.addConstraint(ConstraintKind::Equal, selfTy1, selfTy2, locator); break; case SelfTypeRelationship::Subclass: cs.addConstraint(ConstraintKind::Subtype, selfTy1, selfTy2, locator); break; case SelfTypeRelationship::Superclass: cs.addConstraint(ConstraintKind::Subtype, selfTy2, selfTy1, locator); break; case SelfTypeRelationship::ConformsTo: cs.addConstraint(ConstraintKind::ConformsTo, selfTy1, selfTy2, locator); break; case SelfTypeRelationship::ConformedToBy: cs.addConstraint(ConstraintKind::ConformsTo, selfTy2, selfTy1, locator); break; } switch (checkKind) { case CheckAll: // Check whether the first type is a subtype of the second. cs.addConstraint(ConstraintKind::Subtype, openedType1, openedType2, locator); break; case CheckInput: { // Check whether the first function type's input is a subtype of the // second type's inputs, i.e., can we forward the arguments? auto funcTy1 = openedType1->castTo<FunctionType>(); auto funcTy2 = openedType2->castTo<FunctionType>(); cs.addConstraint(ConstraintKind::Subtype, funcTy1->getInput(), funcTy2->getInput(), locator); break; } } // Solve the system. auto solution = cs.solveSingle(FreeTypeVariableBinding::Allow); // Ban value-to-optional conversions. if (solution && solution->getFixedScore().Data[SK_ValueToOptional] == 0) return true; // Between two imported functions/methods, prefer one with fewer // defaulted arguments. // // FIXME: This is a total hack; we should be comparing based on the // number of default arguments at were actually used. It's only safe to // do this because the count will be zero except when under the // experimental InferDefaultArguments mode of the Clang importer. if (isa<AbstractFunctionDecl>(decl1) && isa<AbstractFunctionDecl>(decl2) && decl1->getClangDecl() && decl2->getClangDecl()) { unsigned defArgsIn1 = countDefaultArguments(cast<AbstractFunctionDecl>(decl1)); unsigned defArgsIn2 = countDefaultArguments(cast<AbstractFunctionDecl>(decl2)); if (defArgsIn1 < defArgsIn2) return true; } return false; }; tc.specializedOverloadComparisonCache[{decl1, decl2}] = compareSpecializations(); } else if (tc.getLangOpts().DebugConstraintSolver) { auto &log = tc.Context.TypeCheckerDebug->getStream(); log << "Found cached comparison: " << tc.specializedOverloadComparisonCache[{decl1, decl2}] << "\n"; } return tc.specializedOverloadComparisonCache[{decl1, decl2}]; }
/// Revert the dependent types within the given generic parameter list. static void revertGenericParamList(TypeChecker &tc, GenericParamList *genericParams) { // Revert the requirements of the generic parameter list. tc.revertGenericRequirements(genericParams->getRequirements()); }
bool operator() (const derivation_rule * d) { return !thea->typecheckDerivationRule(d); };
/// \brief Determine whether the first declaration is as "specialized" as /// the second declaration. /// /// "Specialized" is essentially a form of subtyping, defined below. static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2) { if (tc.getLangOpts().DebugConstraintSolver) { auto &log = tc.Context.TypeCheckerDebug->getStream(); log << "Comparing declarations\n"; decl1->print(log); log << "\nand\n"; decl2->print(log); log << "\n"; } if (!tc.specializedOverloadComparisonCache.count({decl1, decl2})) { auto compareSpecializations = [&] () -> bool { // If the kinds are different, there's nothing we can do. // FIXME: This is wrong for type declarations, which we're skipping // entirely. if (decl1->getKind() != decl2->getKind() || isa<TypeDecl>(decl1)) return false; // A non-generic declaration is more specialized than a generic declaration. if (auto func1 = dyn_cast<AbstractFunctionDecl>(decl1)) { auto func2 = cast<AbstractFunctionDecl>(decl2); if (static_cast<bool>(func1->getGenericParams()) != static_cast<bool>(func2->getGenericParams())) return func2->getGenericParams(); } // A witness is always more specialized than the requirement it satisfies. switch (compareWitnessAndRequirement(tc, dc, decl1, decl2)) { case Comparison::Unordered: break; case Comparison::Better: return true; case Comparison::Worse: return false; } // Members of protocol extensions have special overloading rules. ProtocolDecl *inProtocolExtension1 = decl1->getDeclContext() ->getAsProtocolExtensionContext(); ProtocolDecl *inProtocolExtension2 = decl2->getDeclContext() ->getAsProtocolExtensionContext(); if (inProtocolExtension1 && inProtocolExtension2) { // Both members are in protocol extensions. // Determine whether the 'Self' type from the first protocol extension // satisfies all of the requirements of the second protocol extension. DeclContext *dc1 = decl1->getDeclContext(); DeclContext *dc2 = decl2->getDeclContext(); bool better1 = isProtocolExtensionAsSpecializedAs(tc, dc1, dc2); bool better2 = isProtocolExtensionAsSpecializedAs(tc, dc2, dc1); if (better1 != better2) { return better1; } } else if (inProtocolExtension1 || inProtocolExtension2) { // One member is in a protocol extension, the other is in a concrete type. // Prefer the member in the concrete type. return inProtocolExtension2; } Type type1 = decl1->getInterfaceType(); Type type2 = decl2->getInterfaceType(); /// What part of the type should we check? enum { CheckAll, CheckInput, } checkKind; if (isa<AbstractFunctionDecl>(decl1) || isa<EnumElementDecl>(decl1)) { // Nothing to do: these have the curried 'self' already. if (auto elt = dyn_cast<EnumElementDecl>(decl1)) { checkKind = elt->hasArgumentType() ? CheckInput : CheckAll; } else { checkKind = CheckInput; } } else { // Add a curried 'self' type. assert(!type1->is<GenericFunctionType>() && "Odd generic function type?"); assert(!type2->is<GenericFunctionType>() && "Odd generic function type?"); type1 = addCurriedSelfType(tc.Context, type1, decl1->getDeclContext()); type2 = addCurriedSelfType(tc.Context, type2, decl2->getDeclContext()); // For a subscript declaration, only look at the input type (i.e., the // indices). if (isa<SubscriptDecl>(decl1)) checkKind = CheckInput; else checkKind = CheckAll; } // Construct a constraint system to compare the two declarations. ConstraintSystem cs(tc, dc, ConstraintSystemOptions()); auto locator = cs.getConstraintLocator(nullptr); // FIXME: Locator when anchored on a declaration. // Get the type of a reference to the second declaration. llvm::DenseMap<CanType, TypeVariableType *> unused; Type openedType2; if (auto *funcType = type2->getAs<AnyFunctionType>()) { openedType2 = cs.openFunctionType( funcType, /*numArgumentLabelsToRemove=*/0, locator, /*replacements=*/unused, decl2->getInnermostDeclContext(), decl2->getDeclContext(), /*skipProtocolSelfConstraint=*/false); } else { openedType2 = cs.openType(type2, locator, unused); } // Get the type of a reference to the first declaration, swapping in // archetypes for the dependent types. llvm::DenseMap<CanType, TypeVariableType *> replacements; auto dc1 = decl1->getInnermostDeclContext(); Type openedType1; if (auto *funcType = type1->getAs<AnyFunctionType>()) { openedType1 = cs.openFunctionType( funcType, /*numArgumentLabelsToRemove=*/0, locator, replacements, dc1, decl1->getDeclContext(), /*skipProtocolSelfConstraint=*/false); } else { openedType1 = cs.openType(type1, locator, replacements); } for (const auto &replacement : replacements) { if (auto mapped = dc1->mapTypeIntoContext(replacement.first)) { cs.addConstraint(ConstraintKind::Bind, replacement.second, mapped, locator); } } // Extract the self types from the declarations, if they have them. Type selfTy1; Type selfTy2; if (decl1->getDeclContext()->isTypeContext()) { auto funcTy1 = openedType1->castTo<FunctionType>(); selfTy1 = funcTy1->getInput()->getRValueInstanceType(); openedType1 = funcTy1->getResult(); } if (decl2->getDeclContext()->isTypeContext()) { auto funcTy2 = openedType2->castTo<FunctionType>(); selfTy2 = funcTy2->getInput()->getRValueInstanceType(); openedType2 = funcTy2->getResult(); } // Determine the relationship between the 'self' types and add the // appropriate constraints. The constraints themselves never fail, but // they help deduce type variables that were opened. switch (computeSelfTypeRelationship(tc, dc, decl1->getDeclContext(), decl2->getDeclContext())) { case SelfTypeRelationship::Unrelated: // Skip the self types parameter entirely. break; case SelfTypeRelationship::Equivalent: cs.addConstraint(ConstraintKind::Equal, selfTy1, selfTy2, locator); break; case SelfTypeRelationship::Subclass: cs.addConstraint(ConstraintKind::Subtype, selfTy1, selfTy2, locator); break; case SelfTypeRelationship::Superclass: cs.addConstraint(ConstraintKind::Subtype, selfTy2, selfTy1, locator); break; case SelfTypeRelationship::ConformsTo: cs.addConstraint(ConstraintKind::ConformsTo, selfTy1, cast<ProtocolDecl>(decl2->getDeclContext()) ->getDeclaredType(), locator); break; case SelfTypeRelationship::ConformedToBy: cs.addConstraint(ConstraintKind::ConformsTo, selfTy2, cast<ProtocolDecl>(decl1->getDeclContext()) ->getDeclaredType(), locator); break; } bool fewerEffectiveParameters = false; switch (checkKind) { case CheckAll: // Check whether the first type is a subtype of the second. cs.addConstraint(ConstraintKind::Subtype, openedType1, openedType2, locator); break; case CheckInput: { // Check whether the first function type's input is a subtype of the // second type's inputs, i.e., can we forward the arguments? auto funcTy1 = openedType1->castTo<FunctionType>(); auto funcTy2 = openedType2->castTo<FunctionType>(); SmallVector<CallArgParam, 4> params1 = decomposeParamType(funcTy1->getInput(), decl1, decl1->getDeclContext()->isTypeContext()); SmallVector<CallArgParam, 4> params2 = decomposeParamType(funcTy2->getInput(), decl2, decl2->getDeclContext()->isTypeContext()); unsigned numParams1 = params1.size(); unsigned numParams2 = params2.size(); if (numParams1 > numParams2) return false; for (unsigned i = 0; i != numParams2; ++i) { // If there is no corresponding argument in the first // parameter list... if (i >= numParams1) { // We need either a default argument or a variadic // argument for the first declaration to be more // specialized. if (!params2[i].HasDefaultArgument && !params2[i].isVariadic()) return false; fewerEffectiveParameters = true; continue; } // Labels must match. if (params1[i].Label != params2[i].Label) return false; // If one parameter is variadic and the other is not... if (params1[i].isVariadic() != params2[i].isVariadic()) { // If the first parameter is the variadic one, it's not // more specialized. if (params1[i].isVariadic()) return false; fewerEffectiveParameters = true; } // Check whether the first parameter is a subtype of the second. cs.addConstraint(ConstraintKind::Subtype, params1[i].Ty, params2[i].Ty, locator); } break; } } // Solve the system. auto solution = cs.solveSingle(FreeTypeVariableBinding::Allow); // Ban value-to-optional conversions. if (solution && solution->getFixedScore().Data[SK_ValueToOptional] == 0) return true; // If the first function has fewer effective parameters than the // second, it is more specialized. if (fewerEffectiveParameters) return true; return false; }; tc.specializedOverloadComparisonCache[{decl1, decl2}] = compareSpecializations(); } else if (tc.getLangOpts().DebugConstraintSolver) { auto &log = tc.Context.TypeCheckerDebug->getStream(); log << "Found cached comparison: " << tc.specializedOverloadComparisonCache[{decl1, decl2}] << "\n"; } return tc.specializedOverloadComparisonCache[{decl1, decl2}]; }
bool operator() (const effect * e) { return !thea->typecheckEffect(e); };
bool operator() (const plan_step * p) { return !thea->typecheckActionInstance(p); };
bool operator() (const goal * g) const { return !thea->typecheckGoal(g); };
static void typeCheckFunctionsAndExternalDecls(TypeChecker &TC) { unsigned currentFunctionIdx = 0; unsigned currentExternalDef = TC.Context.LastCheckedExternalDefinition; do { // Type check the body of each of the function in turn. Note that outside // functions must be visited before nested functions for type-checking to // work correctly. for (unsigned n = TC.definedFunctions.size(); currentFunctionIdx != n; ++currentFunctionIdx) { auto *AFD = TC.definedFunctions[currentFunctionIdx]; // HACK: don't type-check the same function body twice. This is // supposed to be handled by just not enqueuing things twice, // but that gets tricky with synthesized function bodies. if (AFD->isBodyTypeChecked()) continue; PrettyStackTraceDecl StackEntry("type-checking", AFD); TC.typeCheckAbstractFunctionBody(AFD); AFD->setBodyTypeCheckedIfPresent(); } for (unsigned n = TC.Context.ExternalDefinitions.size(); currentExternalDef != n; ++currentExternalDef) { auto decl = TC.Context.ExternalDefinitions[currentExternalDef]; if (auto *AFD = dyn_cast<AbstractFunctionDecl>(decl)) { // HACK: don't type-check the same function body twice. This is // supposed to be handled by just not enqueuing things twice, // but that gets tricky with synthesized function bodies. if (AFD->isBodyTypeChecked()) continue; PrettyStackTraceDecl StackEntry("type-checking", AFD); TC.typeCheckAbstractFunctionBody(AFD); continue; } if (isa<NominalTypeDecl>(decl)) { TC.handleExternalDecl(decl); continue; } if (isa<VarDecl>(decl)) continue; llvm_unreachable("Unhandled external definition kind"); } // Validate the contents of any referenced nominal types for SIL's purposes. // Note: if we ever start putting extension members in vtables, we'll need // to validate those members too. // FIXME: If we're not planning to run SILGen, this is wasted effort. while (!TC.TypesToFinalize.empty()) { auto nominal = TC.TypesToFinalize.pop_back_val(); if (nominal->isInvalid() || TC.Context.hadError()) continue; finalizeType(TC, nominal); } // Complete any conformances that we used. for (unsigned i = 0; i != TC.UsedConformances.size(); ++i) { auto conformance = TC.UsedConformances[i]; if (conformance->isIncomplete()) TC.checkConformance(conformance); } TC.UsedConformances.clear(); } while (currentFunctionIdx < TC.definedFunctions.size() || currentExternalDef < TC.Context.ExternalDefinitions.size() || !TC.TypesToFinalize.empty() || !TC.UsedConformances.empty()); // FIXME: Horrible hack. Store this somewhere more appropriate. TC.Context.LastCheckedExternalDefinition = currentExternalDef; // Compute captures for functions and closures we visited. for (AnyFunctionRef closure : TC.ClosuresWithUncomputedCaptures) { TC.computeCaptures(closure); } for (AbstractFunctionDecl *FD : reversed(TC.definedFunctions)) { TC.computeCaptures(FD); } // Check error-handling correctness for all the functions defined in // this file. This can depend on all of their interior function // bodies having been type-checked. for (AbstractFunctionDecl *FD : TC.definedFunctions) { TC.checkFunctionErrorHandling(FD); } for (auto decl : TC.Context.ExternalDefinitions) { if (auto fn = dyn_cast<AbstractFunctionDecl>(decl)) { TC.checkFunctionErrorHandling(fn); } } }
bool checkPlan (const std::string& domain_file, const std::string& problem_file, std::stringstream& plan) { try { current_analysis = &an_analysis; //an_analysis.const_tab.symbol_put(""); //for events - undefined symbol Silent = false; errorCount = 0; Verbose = false; ContinueAnyway = false; ErrorReport = false; InvariantWarnings = false; makespanDefault = false; bool CheckDPs = true; bool giveAdvice = true; double tolerance = 0.01; bool lengthDefault = true; string s; std::ifstream domainFile (domain_file.c_str()); if (!domainFile) { std::cerr << "Bad domain file!\n"; exit (1); }; yfl = new yyFlexLexer (&domainFile, &cout); yydebug = 0; yyparse(); delete yfl; if (!an_analysis.the_domain) { std::cerr << "Problem in domain definition!\n"; exit (1); }; TypeChecker tc (current_analysis); bool typesOK = tc.typecheckDomain(); if (!typesOK) { std::cerr << "Type problem in domain description!\n"; exit (1); }; std::ifstream problemFile (problem_file.c_str()); if (!problemFile) { std::cerr << "Bad problem file!\n"; exit (1); }; yfl = new yyFlexLexer (&problemFile, &cout); yyparse(); delete yfl; if (!tc.typecheckProblem()) { std::cerr << "Type problem in problem specification!\n"; exit (1); }; const DerivationRules * derivRules = new DerivationRules (an_analysis.the_domain->drvs, an_analysis.the_domain->ops); if (CheckDPs && !derivRules->checkDerivedPredicates()) { exit (1); }; executePlan (plan, tc, derivRules, tolerance, lengthDefault, giveAdvice); delete derivRules; } catch (exception & e) { std::cerr << "Error: " << e.what() << "\n"; an_analysis.error_list.report(); return 2; }; return errorCount == 0; };
static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC) { unsigned currentFunctionIdx = 0; unsigned currentExternalDef = TC.Context.LastCheckedExternalDefinition; unsigned currentSynthesizedDecl = SF.LastCheckedSynthesizedDecl; do { // Type check conformance contexts. for (unsigned i = 0; i != TC.ConformanceContexts.size(); ++i) { auto decl = TC.ConformanceContexts[i]; if (auto *ext = dyn_cast<ExtensionDecl>(decl)) TC.checkConformancesInContext(ext, ext); else { auto *ntd = cast<NominalTypeDecl>(decl); TC.checkConformancesInContext(ntd, ntd); // Finally, we can check classes for missing initializers. if (auto *classDecl = dyn_cast<ClassDecl>(ntd)) TC.maybeDiagnoseClassWithoutInitializers(classDecl); } } TC.ConformanceContexts.clear(); // Type check the body of each of the function in turn. Note that outside // functions must be visited before nested functions for type-checking to // work correctly. for (unsigned n = TC.definedFunctions.size(); currentFunctionIdx != n; ++currentFunctionIdx) { auto *AFD = TC.definedFunctions[currentFunctionIdx]; TC.typeCheckAbstractFunctionBody(AFD); } // Synthesize any necessary function bodies. // FIXME: If we're not planning to run SILGen, this is wasted effort. while (!TC.FunctionsToSynthesize.empty()) { auto function = TC.FunctionsToSynthesize.back().second; TC.FunctionsToSynthesize.pop_back(); if (function.getDecl()->isInvalid() || TC.Context.hadError()) continue; TC.synthesizeFunctionBody(function); } // Type check external definitions. for (unsigned n = TC.Context.ExternalDefinitions.size(); currentExternalDef != n; ++currentExternalDef) { auto decl = TC.Context.ExternalDefinitions[currentExternalDef]; if (auto *AFD = dyn_cast<AbstractFunctionDecl>(decl)) { TC.typeCheckAbstractFunctionBody(AFD); TC.checkFunctionErrorHandling(AFD); continue; } if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) { (void)nominal->getAllConformances(); continue; } if (isa<VarDecl>(decl)) continue; llvm_unreachable("Unhandled external definition kind"); } // Complete any protocol requirement signatures that were delayed // because the protocol was validated via validateDeclForNameLookup(). while (!TC.DelayedRequirementSignatures.empty()) { auto decl = TC.DelayedRequirementSignatures.pop_back_val(); if (decl->isInvalid() || TC.Context.hadError()) continue; TC.validateDecl(decl); } // Validate any referenced declarations for SIL's purposes. // Note: if we ever start putting extension members in vtables, we'll need // to validate those members too. // FIXME: If we're not planning to run SILGen, this is wasted effort. while (TC.NextDeclToFinalize < TC.DeclsToFinalize.size()) { auto decl = TC.DeclsToFinalize[TC.NextDeclToFinalize++]; if (decl->isInvalid()) continue; // If we've already encountered an error, don't finalize declarations // from other source files. if (TC.Context.hadError() && decl->getDeclContext()->getParentSourceFile() != &SF) continue; TC.finalizeDecl(decl); } // Type check synthesized functions and their bodies. for (unsigned n = SF.SynthesizedDecls.size(); currentSynthesizedDecl != n; ++currentSynthesizedDecl) { auto decl = SF.SynthesizedDecls[currentSynthesizedDecl]; TC.typeCheckDecl(decl); } // Ensure that the requirements of the given conformance are // fully checked. for (unsigned i = 0; i != TC.PartiallyCheckedConformances.size(); ++i) { auto conformance = TC.PartiallyCheckedConformances[i]; TC.checkConformanceRequirements(conformance); } TC.PartiallyCheckedConformances.clear(); // Complete any conformances that we used. for (unsigned i = 0; i != TC.UsedConformances.size(); ++i) { auto conformance = TC.UsedConformances[i]; if (conformance->isIncomplete()) TC.checkConformance(conformance); } TC.UsedConformances.clear(); } while (currentFunctionIdx < TC.definedFunctions.size() || currentExternalDef < TC.Context.ExternalDefinitions.size() || currentSynthesizedDecl < SF.SynthesizedDecls.size() || !TC.FunctionsToSynthesize.empty() || TC.NextDeclToFinalize < TC.DeclsToFinalize.size() || !TC.ConformanceContexts.empty() || !TC.DelayedRequirementSignatures.empty() || !TC.UsedConformances.empty() || !TC.PartiallyCheckedConformances.empty()); // FIXME: Horrible hack. Store this somewhere more appropriate. TC.Context.LastCheckedExternalDefinition = currentExternalDef; SF.LastCheckedSynthesizedDecl = currentSynthesizedDecl; // Now that all types have been finalized, run any delayed // circularity checks. // This has been written carefully to fail safe + finitely if // for some reason a type gets re-delayed in a non-assertions // build in an otherwise successful build. // Types can be redelayed in a failing build because we won't // type-check required declarations from different files. for (size_t i = 0, e = TC.DelayedCircularityChecks.size(); i != e; ++i) { TC.checkDeclCircularity(TC.DelayedCircularityChecks[i]); assert((e == TC.DelayedCircularityChecks.size() || TC.Context.hadError()) && "circularity checking for type was re-delayed!"); } TC.DelayedCircularityChecks.clear(); // Compute captures for functions and closures we visited. for (AnyFunctionRef closure : TC.ClosuresWithUncomputedCaptures) { TC.computeCaptures(closure); } TC.ClosuresWithUncomputedCaptures.clear(); for (AbstractFunctionDecl *FD : reversed(TC.definedFunctions)) { TC.computeCaptures(FD); } // Check error-handling correctness for all the functions defined in // this file. This can depend on all of their interior function // bodies having been type-checked. for (AbstractFunctionDecl *FD : TC.definedFunctions) { TC.checkFunctionErrorHandling(FD); } TC.definedFunctions.clear(); }
int main(int argc, const char **argv ) { pgm_name = argv[0]; #ifdef YYDEBUG // yydebug = 1; #endif std::string temp; if( argc > 1) { if(strstr(argv[1],".java") != NULL && strcmp(strstr(argv[1],".java"),".java") == 0) { yyin = fopen( argv[1], "r"); // printf("%s\n",argv[1]); temp = std::string(argv[1]); if(yyin == NULL) fatal( "Cannot open input file: ", argv[1]); //fatal error } else { fatal( "Invalid file type: ", argv[1]); //fatal error } } else { fatal("No input file provided: ", argv[0]); } classDecl = NULL; yyparse(); //Parse the input file, creating the AstTree DictBuilder *dictBuilder = new DictBuilder(); if(classDecl != NULL) { classDecl->accept( dictBuilder ); //Build the Symbol Table using the AstTree } else { fatal("Error parsing file. Compilation aborted.", ""); } TypeChecker *typeCheck = new TypeChecker(dictBuilder->getSymbolTable(), 0, temp.substr(0,temp.length()-5).c_str()); if(!dictBuilder->getError()) { classDecl->accept(typeCheck); //Perform Various Semantic Checks } else { fatal("Error while building scopes. Compilation aborted.", ""); } if(!typeCheck->getError()) { classDecl->accept(new JasminTranslator()); //Translate Program to .class file } else { fatal("Error during type checking. Compilation aborted.", ""); } return 0; }