diff options
| author | Yong He <yonghe@outlook.com> | 2017-11-05 16:39:38 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-11-05 16:39:38 -0500 |
| commit | 296e89ca4f3d6d99126bf2ee59666bc946add431 (patch) | |
| tree | bff41e36c9b6843d83a5ca5e83645310be6687f3 /source/slang/check.cpp | |
| parent | c6fb1de9547bd24a693915b758cc35499f1d949f (diff) | |
| parent | ff7c46a11787ca6ecebf0a224772a41efef33fc0 (diff) | |
Merge pull request #243 from csyonghe/master
Adding associated types
Diffstat (limited to 'source/slang/check.cpp')
| -rw-r--r-- | source/slang/check.cpp | 281 |
1 files changed, 225 insertions, 56 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 65b2295cc..ed2ed4a1b 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -140,6 +140,15 @@ namespace Slang return result; } + RefPtr<DeclRefType> getExprDeclRefType(Expr * expr) + { + if (auto typetype = expr->type->As<TypeType>()) + return typetype->type.As<DeclRefType>(); + else + return expr->type->As<DeclRefType>(); + } + + RefPtr<Expr> ConstructDeclRefExpr( DeclRef<Decl> declRef, RefPtr<Expr> baseExpr, @@ -147,26 +156,63 @@ namespace Slang { if (baseExpr) { + RefPtr<Expr> expr; + DeclRef<Decl> *declRefOut; if (baseExpr->type->As<TypeType>()) { - auto expr = new StaticMemberExpr(); - expr->loc = loc; - expr->BaseExpression = baseExpr; - expr->name = declRef.GetName(); - expr->type = GetTypeForDeclRef(declRef); - expr->declRef = declRef; - return expr; + auto sexpr = new StaticMemberExpr(); + sexpr->loc = loc; + sexpr->BaseExpression = baseExpr; + sexpr->name = declRef.GetName(); + sexpr->declRef = declRef; + declRefOut = &sexpr->declRef; + expr = sexpr; } else { - auto expr = new MemberExpr(); - expr->loc = loc; - expr->BaseExpression = baseExpr; - expr->name = declRef.GetName(); - expr->type = GetTypeForDeclRef(declRef); - expr->declRef = declRef; + auto sexpr = new MemberExpr(); + sexpr->loc = loc; + sexpr->BaseExpression = baseExpr; + sexpr->name = declRef.GetName(); + sexpr->declRef = declRef; + declRefOut = &sexpr->declRef; + expr = sexpr; + } + + RefPtr<ThisTypeSubstitution> baseThisTypeSubst; + if (auto baseDeclRefExpr = baseExpr->As<DeclRefExpr>()) + { + baseThisTypeSubst = getThisTypeSubst(baseDeclRefExpr->declRef, false); + if (auto baseAssocType = baseDeclRefExpr->declRef.As<AssocTypeDecl>()) + { + baseThisTypeSubst = new ThisTypeSubstitution(); + baseThisTypeSubst->sourceType = baseDeclRefExpr->type.type; + if (auto typetype = baseThisTypeSubst->sourceType.As<TypeType>()) + baseThisTypeSubst->sourceType = typetype->type; + } + } + if (auto assocTypeDecl = declRef.As<AssocTypeDecl>()) + { + auto newThisTypeSubst = new ThisTypeSubstitution(); + if (baseThisTypeSubst) + newThisTypeSubst->sourceType = baseThisTypeSubst->sourceType; + expr->type = GetTypeForDeclRef(DeclRef<AssocTypeDecl>(assocTypeDecl.getDecl(), newThisTypeSubst)); + auto declOutThisTypeSubst = getNewThisTypeSubst(*declRefOut); + if (baseThisTypeSubst) + declOutThisTypeSubst->sourceType = baseThisTypeSubst->sourceType; return expr; } + + // propagate "this-type" substitutions + if (baseThisTypeSubst) + { + if (auto declRefExpr = expr.As<DeclRefExpr>()) + { + getNewThisTypeSubst(declRefExpr->declRef)->sourceType = baseThisTypeSubst->sourceType; + } + } + expr->type = GetTypeForDeclRef(declRef); + return expr; } else { @@ -174,6 +220,21 @@ namespace Slang expr->loc = loc; expr->name = declRef.GetName(); expr->type = GetTypeForDeclRef(declRef); + if (auto exprDeclRefType = getExprDeclRefType(expr)) + { + if (auto genParmDecl = exprDeclRefType->declRef.As<GenericTypeParamDecl>()) + { + // if this is a reference to generic type param, insert a this-type substitution + auto exprType = GetTypeForDeclRef(declRef); + auto thisSubst = new ThisTypeSubstitution(); + if (auto typetype = exprType.type.As<TypeType>()) + thisSubst->sourceType = typetype->type; + else + thisSubst->sourceType = exprType.type; + thisSubst->outer = declRef.substitutions; + declRef.substitutions = thisSubst; + } + } expr->declRef = declRef; return expr; } @@ -401,7 +462,7 @@ namespace Slang DeclRef<GenericDecl> genericDeclRef, List<RefPtr<Expr>> const& args) { - RefPtr<Substitutions> subst = new Substitutions(); + RefPtr<GenericSubstitution> subst = new GenericSubstitution(); subst->genericDecl = genericDeclRef.getDecl(); subst->outer = genericDeclRef.substitutions; @@ -892,8 +953,6 @@ namespace Slang } // - - if (auto toDeclRefType = toType->As<DeclRefType>()) { auto toTypeDeclRef = toDeclRefType->declRef; @@ -911,8 +970,42 @@ namespace Slang return true; } } - } + else if (auto genParamDeclRef = toTypeDeclRef.As<GenericTypeParamDecl>()) + { + // We need to enumerate the constraints placed on this type by its outer + // generic declaration, and see if any of them guarantees that we + // satisfy the given interface.. + auto genericDeclRef = genParamDeclRef.GetParent().As<GenericDecl>(); + SLANG_ASSERT(genericDeclRef); + + for (auto constraintDeclRef : getMembersOfType<GenericTypeConstraintDecl>(genericDeclRef)) + { + auto sub = GetSub(constraintDeclRef); + auto sup = GetSup(constraintDeclRef); + auto subDeclRef = sub->As<DeclRefType>(); + if (!subDeclRef) + continue; + if (subDeclRef->declRef != genParamDeclRef) + continue; + auto supDeclRefType = sup->As<DeclRefType>(); + if (supDeclRefType) + { + auto toInterfaceDeclRef = supDeclRefType->declRef.As<InterfaceDecl>(); + if (DoesTypeConformToInterface(fromType, toInterfaceDeclRef)) + { + if (outToExpr) + *outToExpr = CreateImplicitCastExpr(toType, fromExpr); + if (outCost) + *outCost = kConversionCost_CastToInterface; + return true; + } + } + } + + } + + } // Look for an initializer/constructor declaration in the target type, // which is marked as usable for implicit conversion, and which takes // the source type as an argument. @@ -1224,6 +1317,14 @@ namespace Slang checkDecl(genericDecl->inner); } + void visitGenericTypeConstraintDecl(GenericTypeConstraintDecl * genericConstraintDecl) + { + // check the type being inherited from + auto base = genericConstraintDecl->sup; + base = TranslateTypeNode(base); + genericConstraintDecl->sup = base; + } + void visitInheritanceDecl(InheritanceDecl* inheritanceDecl) { // check the type being inherited from @@ -1287,11 +1388,6 @@ namespace Slang // These are only used in the stdlib, so no checking is needed for now } - void visitGenericTypeConstraintDecl(GenericTypeConstraintDecl*) - { - // These are only used in the stdlib, so no checking is needed for now - } - void visitModifier(Modifier*) { // Do nothing with modifiers for now @@ -1538,7 +1634,50 @@ namespace Slang requiredInitDecl); } } + else if (auto subStructTypeDecl = dynamic_cast<AggTypeDecl*>(memberDecl)) + { + // this is a sub type (e.g. nested struct declaration) in an aggregate type + // check if this sub type declaration satisfies the constraints defined by the associated type + if (auto requiredTypeDeclRef = requiredMemberDeclRef.As<AssocTypeDecl>()) + { + bool conformance = true; + for (auto & inheritanceDecl : requiredTypeDeclRef.getDecl()->getMembersOfType<InheritanceDecl>()) + { + conformance = conformance && checkConformance(subStructTypeDecl, inheritanceDecl.Ptr()); + } + return conformance; + } + } + else if (auto typedefDecl = dynamic_cast<TypeDefDecl*>(memberDecl)) + { + // this is a type-def decl in an aggregate type + // check if the specified type satisfies the constraints defined by the associated type + if (auto requiredTypeDecl = requiredMemberDeclRef.As<AssocTypeDecl>()) + { + auto constraintList = requiredTypeDecl.getDecl()->getMembersOfType<InheritanceDecl>(); + if (constraintList.Count()) + { + auto declRefType = typedefDecl->type->AsDeclRefType(); + if (!declRefType) + return false; + auto structTypeDecl = declRefType->declRef.getDecl()->As<AggTypeDecl>(); + if (!structTypeDecl) + return false; + //TODO: What do we do if type is a generic specialization? + // i.e. if the struct defines typedef Generic<float> T; + // how to check if T satisfies the associatedtype constraints? + // the code below will only work when T is defined to be a simple aggregated type (no generics). + bool conformance = true; + for (auto & inheritanceDecl : constraintList) + { + conformance = conformance && checkConformance(structTypeDecl, inheritanceDecl.Ptr()); + } + return conformance; + } + return true; + } + } // Default: just assume that thing aren't being satisfied. return false; } @@ -1623,11 +1762,13 @@ namespace Slang // declares conformance to the interface `interfaceDeclRef`, // (via the given `inheritanceDecl`) actually provides // members to satisfy all the requirements in the interface. - void checkInterfaceConformance( + bool checkInterfaceConformance( AggTypeDecl* typeDecl, InheritanceDecl* inheritanceDecl, DeclRef<InterfaceDecl> interfaceDeclRef) { + bool result = true; + // We need to check the declaration of the interface // before we can check that we conform to it. EnsureDecl(interfaceDeclRef.getDecl()); @@ -1654,7 +1795,7 @@ namespace Slang // to the inherited interface. // // TODO: we *really* need a linearization step here!!!! - checkConformanceToType( + result = result && checkConformanceToType( typeDecl, inheritanceDecl, getBaseType(requiredInheritanceDeclRef)); @@ -1670,16 +1811,20 @@ namespace Slang requiredMemberDeclRef); if (!conformanceWitness) + { + result = false; continue; + } // Store that witness into a table stored on the `inheritnaceDecl` // so that it can be used for downstream code generation. inheritanceDecl->requirementWitnesses.Add(requiredMemberDeclRef, conformanceWitness); } + return result; } - void checkConformanceToType( + bool checkConformanceToType( AggTypeDecl* typeDecl, InheritanceDecl* inheritanceDecl, Type* baseType) @@ -1692,29 +1837,29 @@ namespace Slang // The type is stating that it conforms to an interface. // We need to check that it provides all of the members // required by that interface. - checkInterfaceConformance( + return checkInterfaceConformance( typeDecl, inheritanceDecl, baseInterfaceDeclRef); - return; } } getSink()->diagnose(inheritanceDecl, Diagnostics::unimplemented, "type not supported for inheritance"); + return false; } // Check that the type declaration `typeDecl`, which // declares that it inherits from another type via // `inheritanceDecl` actually does what it needs to // for that inheritance to be valid. - void checkConformance( + bool checkConformance( AggTypeDecl* typeDecl, InheritanceDecl* inheritanceDecl) { // Look at the type being inherited from, and validate // appropriately. auto baseType = inheritanceDecl->base.type; - checkConformanceToType(typeDecl, inheritanceDecl, baseType); + return checkConformanceToType(typeDecl, inheritanceDecl, baseType); } void visitAggTypeDecl(AggTypeDecl* decl) @@ -1758,6 +1903,11 @@ namespace Slang // Don't check that an interface conforms to the // things it inherits from. } + else if (auto assocTypeDecl = dynamic_cast<AssocTypeDecl*>(decl)) + { + // Don't check that an associated type decl conforms to the + // things it inherits from. + } else { // For non-interface types we need to check conformance. @@ -1794,6 +1944,24 @@ namespace Slang decl->SetCheckState(DeclCheckState::Checked); } + void visitAssocTypeDecl(AssocTypeDecl* decl) + { + if (decl->IsChecked(DeclCheckState::Checked)) return; + decl->SetCheckState(DeclCheckState::CheckedHeader); + + // assoctype only allowed in an interface + auto interfaceDecl = decl->ParentDecl->As<InterfaceDecl>(); + if (!interfaceDecl) + getSink()->diagnose(decl, Slang::Diagnostics::assocTypeInInterfaceOnly); + + // Now check all of the member declarations. + for (auto member : decl->Members) + { + checkDecl(member); + } + decl->SetCheckState(DeclCheckState::Checked); + } + void checkStmt(Stmt* stmt) { if (!stmt) return; @@ -1806,7 +1974,7 @@ namespace Slang return; VisitFunctionDeclaration(functionNode); - // TODO: This should really onlye set "checked header" + // TODO: This should really only set "checked header" functionNode->SetCheckState(DeclCheckState::Checked); // TODO: should put the checking of the body onto a "work list" @@ -1977,10 +2145,10 @@ namespace Slang return true; } - RefPtr<Substitutions> createDummySubstitutions( + RefPtr<GenericSubstitution> createDummySubstitutions( GenericDecl* genericDecl) { - RefPtr<Substitutions> subst = new Substitutions(); + RefPtr<GenericSubstitution> subst = new GenericSubstitution(); subst->genericDecl = genericDecl; for (auto dd : genericDecl->Members) { @@ -2239,7 +2407,6 @@ namespace Slang { if (functionNode->IsChecked(DeclCheckState::CheckedHeader)) return; functionNode->SetCheckState(DeclCheckState::CheckingHeader); - this->function = functionNode; auto returnType = CheckProperType(functionNode->ReturnType); functionNode->ReturnType = returnType; @@ -2996,7 +3163,7 @@ namespace Slang session, "Vector").As<GenericDecl>(); auto vectorTypeDecl = vectorGenericDecl->inner; - auto substitutions = new Substitutions(); + auto substitutions = new GenericSubstitution(); substitutions->genericDecl = vectorGenericDecl.Ptr(); substitutions->args.Add(elementType); substitutions->args.Add(elementCount); @@ -3742,7 +3909,7 @@ namespace Slang // Consruct a reference to the extension with our constraint variables // as the - RefPtr<Substitutions> solvedSubst = new Substitutions(); + RefPtr<GenericSubstitution> solvedSubst = new GenericSubstitution(); solvedSubst->genericDecl = genericDeclRef.getDecl(); solvedSubst->outer = genericDeclRef.substitutions; solvedSubst->args = args; @@ -4011,8 +4178,9 @@ namespace Slang // We will go ahead and hang onto the arguments that we've // already checked, since downstream validation might need // them. - candidate.subst = new Substitutions(); - auto& checkedArgs = candidate.subst->args; + auto genSubst = new GenericSubstitution(); + candidate.subst = genSubst; + auto& checkedArgs = genSubst->args; int aa = 0; for (auto memberRef : getMembers(genericDeclRef)) @@ -4185,7 +4353,7 @@ namespace Slang // We should have the existing arguments to the generic // handy, so that we can construct a substitution list. - RefPtr<Substitutions> subst = candidate.subst; + RefPtr<GenericSubstitution> subst = candidate.subst.As<GenericSubstitution>(); assert(subst); subst->genericDecl = genericDeclRef.getDecl(); @@ -4252,7 +4420,7 @@ namespace Slang RefPtr<Expr> createGenericDeclRef( RefPtr<Expr> baseExpr, RefPtr<Expr> originalExpr, - RefPtr<Substitutions> subst) + RefPtr<GenericSubstitution> subst) { auto baseDeclRefExpr = baseExpr.As<DeclRefExpr>(); if (!baseDeclRefExpr) @@ -4364,7 +4532,7 @@ namespace Slang return createGenericDeclRef( baseExpr, context.originalExpr, - candidate.subst); + candidate.subst.As<GenericSubstitution>()); break; default: @@ -4659,22 +4827,23 @@ namespace Slang // They must both be NULL or non-NULL if (!fst || !snd) return fst == snd; - + auto fstGen = fst.As<GenericSubstitution>(); + auto sndGen = snd.As<GenericSubstitution>(); // They must be specializing the same generic - if (fst->genericDecl != snd->genericDecl) + if (fstGen->genericDecl != sndGen->genericDecl) return false; // Their arguments must unify - SLANG_RELEASE_ASSERT(fst->args.Count() == snd->args.Count()); - UInt argCount = fst->args.Count(); + SLANG_RELEASE_ASSERT(fstGen->args.Count() == sndGen->args.Count()); + UInt argCount = fstGen->args.Count(); for (UInt aa = 0; aa < argCount; ++aa) { - if (!TryUnifyVals(constraints, fst->args[aa], snd->args[aa])) + if (!TryUnifyVals(constraints, fstGen->args[aa], sndGen->args[aa])) return false; } // Their "base" specializations must unify - if (!TryUnifySubstitutions(constraints, fst->outer, snd->outer)) + if (!TryUnifySubstitutions(constraints, fstGen->outer, sndGen->outer)) return false; return true; @@ -5229,11 +5398,12 @@ namespace Slang if( parentGenericDeclRef ) { SLANG_RELEASE_ASSERT(declRef.substitutions); - SLANG_RELEASE_ASSERT(declRef.substitutions->genericDecl == parentGenericDeclRef.getDecl()); + auto genSubst = declRef.substitutions.As<GenericSubstitution>(); + SLANG_RELEASE_ASSERT(genSubst->genericDecl == parentGenericDeclRef.getDecl()); sb << "<"; bool first = true; - for(auto arg : declRef.substitutions->args) + for(auto arg : genSubst->args) { if(!first) sb << ", "; formatVal(sb, arg); @@ -5660,7 +5830,6 @@ namespace Slang RefPtr<Expr> CheckInvokeExprWithCheckedOperands(InvokeExpr *expr) { - auto rs = ResolveInvoke(expr); if (auto invoke = dynamic_cast<InvokeExpr*>(rs.Ptr())) { @@ -5695,6 +5864,7 @@ namespace Slang { // check the base expression first expr->FunctionExpr = CheckExpr(expr->FunctionExpr); + // Next check the argument expressions for (auto & arg : expr->Arguments) @@ -6419,6 +6589,11 @@ namespace Slang *outTypeResult = type; return QualType(getTypeType(type)); } + else if (auto funcDeclRef = declRef.As<CallableDecl>()) + { + auto type = getFuncType(session, funcDeclRef); + return QualType(type); + } else if (auto constraintDeclRef = declRef.As<GenericTypeConstraintDecl>()) { // When we access a constraint or an inheritance decl (as a member), @@ -6427,12 +6602,6 @@ namespace Slang auto type = GetSup(constraintDeclRef); return QualType(type); } - else if (auto funcDeclRef = declRef.As<CallableDecl>()) - { - auto type = getFuncType(session, funcDeclRef); - return QualType(type); - } - if( sink ) { sink->diagnose(declRef, Diagnostics::unimplemented, "cannot form reference to this kind of declaration"); @@ -6476,7 +6645,7 @@ namespace Slang if(decl != genericDecl->inner) return parentSubst; - RefPtr<Substitutions> subst = new Substitutions(); + RefPtr<GenericSubstitution> subst = new GenericSubstitution(); subst->genericDecl = genericDecl; subst->outer = parentSubst; |
