From 0a3656788473244b4760791c4129a4080a6631f6 Mon Sep 17 00:00:00 2001 From: Yong He Date: Fri, 3 Nov 2017 18:55:03 -0400 Subject: associatedtypes: generating almost correct HLSL, but is not calling correctly mangled function. --- source/slang/check.cpp | 157 +++++++++++++++++++++++++++++++++++++++---- source/slang/emit.cpp | 5 ++ source/slang/lower-to-ir.cpp | 7 ++ source/slang/lower.cpp | 4 ++ source/slang/slang.cpp | 1 + source/slang/slang.natvis | 21 ++++++ source/slang/syntax.cpp | 120 ++++++++++++++++++++++++++++++--- source/slang/syntax.h | 3 +- source/slang/type-defs.h | 32 +++++++++ 9 files changed, 329 insertions(+), 21 deletions(-) (limited to 'source') diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 137b1c451..240ac2d05 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -148,13 +148,15 @@ namespace Slang if (baseExpr) { RefPtr expr; - + DeclRef *declRefOut; if (baseExpr->type->As()) { auto sexpr = new StaticMemberExpr(); sexpr->loc = loc; sexpr->BaseExpression = baseExpr; sexpr->name = declRef.GetName(); + sexpr->declRef = declRef; + declRefOut = &sexpr->declRef; expr = sexpr; } else @@ -164,24 +166,88 @@ namespace Slang sexpr->BaseExpression = baseExpr; sexpr->name = declRef.GetName(); sexpr->declRef = declRef; + declRefOut = &sexpr->declRef; expr = sexpr; } if (auto assocTypeDecl = declRef.As()) { RefPtr subst = new ThisTypeSubstitution(); - subst->sourceType = baseExpr->type.type; + auto baseDeclRefType = baseExpr->type.type.As(); + if (baseDeclRefType && !baseDeclRefType->declRef.getDecl()->As()) + { + // if base type is not an interface, insert a non-trivial this_type substitution + subst->sourceType = baseExpr->type.type; + } + else + { + // otherwise, insert a null this type substitution, indicating that "this_type" is currently a free variable + subst->sourceType = nullptr; + } if (auto typeType = subst->sourceType.As()) subst->sourceType = typeType->type; expr->type = GetTypeForDeclRef(DeclRef(assocTypeDecl.getDecl(), subst)); + declRefOut->substitutions = subst; + return expr; } else if (auto constraintDecl = declRef.As()) { - expr->type = baseExpr->type; + expr = baseExpr; + if (auto declRefExpr = expr.As()) + declRefOut = &declRefExpr->declRef; + else + return expr; + RefPtr declRefType; + if (auto typeType = baseExpr->type.type.As()) + declRefType = typeType->type->As(); + else + declRefType = baseExpr->type.type.As(); + + if (declRefType) + { + RefPtr subst = new ThisTypeSubstitution(); + subst->sourceType = declRefType; + auto exprType = DeclRefType::Create(getSession(), DeclRef(declRefType->declRef.decl, declRef.substitutions)); + subst->outer = declRef.substitutions; + exprType->declRef.substitutions = subst; + declRefOut->substitutions = subst; + expr->type = exprType; + return expr; + } } - else + else if (auto callableDeclRef = declRef.As()) { + // propagate ThisTypeSubstitution + RefPtr declRefType; + if (auto typeType = baseExpr->type.type.As()) + declRefType = typeType->type->As(); + else + declRefType = baseExpr->type.type.As(); + RefPtr thisSubst; + if (declRefType) + { + auto subst = declRefType->declRef.substitutions; + while (subst) + { + thisSubst = subst.As(); + if (thisSubst) + { + break; + } + subst = subst->outer; + } + } + if (thisSubst) + { + auto newThisSubst = new ThisTypeSubstitution(); + newThisSubst->sourceType = thisSubst->sourceType; + newThisSubst->outer = declRefType->declRef.substitutions; + declRef.substitutions = thisSubst; + } expr->type = GetTypeForDeclRef(declRef); + *declRefOut = declRef; } + + expr->type = GetTypeForDeclRef(declRef); return expr; } else @@ -908,12 +974,36 @@ namespace Slang } // - - if (auto toDeclRefType = toType->As()) { auto toTypeDeclRef = toDeclRefType->declRef; - if (auto interfaceDeclRef = toTypeDeclRef.As()) + if (auto assocDeclRef = toTypeDeclRef.As()) + { + if (auto fromTypeDeclRefType = fromType->As()) + { + if (auto thisSubst = assocDeclRef.substitutions.As()) + { + if (auto fromThisSubst = fromTypeDeclRefType->declRef.substitutions.As()) + { + if (!thisSubst->sourceType || !fromThisSubst->sourceType) + return true; + if (CanCoerce(thisSubst->sourceType.As(), fromThisSubst->sourceType.As(), outCost)) + { + if (outCost) + *outCost = kConversionCost_CastToInterface; + if (outToExpr) + *outToExpr = fromExpr; + return true; + } + } + else + return true; + } + else + return true; + } + } + else if (auto interfaceDeclRef = toTypeDeclRef.As()) { // Trying to convert to an interface type. // @@ -927,8 +1017,42 @@ namespace Slang return true; } } - } + else if (auto genParamDeclRef = toTypeDeclRef.As()) + { + // 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(); + SLANG_ASSERT(genericDeclRef); + + for (auto constraintDeclRef : getMembersOfType(genericDeclRef)) + { + auto sub = GetSub(constraintDeclRef); + auto sup = GetSup(constraintDeclRef); + auto subDeclRef = sub->As(); + if (!subDeclRef) + continue; + if (subDeclRef->declRef != genParamDeclRef) + continue; + auto supDeclRefType = sup->As(); + if (supDeclRefType) + { + auto toInterfaceDeclRef = supDeclRefType->declRef.As(); + 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. @@ -1891,6 +2015,8 @@ namespace Slang void visitFuncDecl(FuncDecl *functionNode) { + if (functionNode->nameAndLoc.name->text == "test") + printf("break"); if (functionNode->IsChecked(DeclCheckState::Checked)) return; @@ -4384,7 +4510,7 @@ namespace Slang callExpr->FunctionExpr = baseExpr; - callExpr->type = QualType(candidate.resultType);// QualType(baseExpr->type->As()->resultType); + callExpr->type = QualType(candidate.resultType); // A call may yield an l-value, and we should take a look at the candidate to be sure if(auto subscriptDeclRef = candidate.item.declRef.As()) @@ -4575,9 +4701,7 @@ namespace Slang OverloadCandidate candidate; candidate.flavor = OverloadCandidate::Flavor::Func; candidate.item = item; - auto baseExpr = ConstructLookupResultExpr( - item, context.baseExpr, context.funcLoc); - candidate.resultType = baseExpr->type->As()->resultType; // GetResultType(funcDeclRef); + candidate.resultType = GetResultType(funcDeclRef); AddOverloadCandidate(context, candidate); } @@ -5739,6 +5863,9 @@ namespace Slang RefPtr visitInvokeExpr(InvokeExpr *expr) { + if (auto mbrExpr = expr->FunctionExpr->As()) + if (mbrExpr->name->text == "add") + printf("break"); // check the base expression first expr->FunctionExpr = CheckExpr(expr->FunctionExpr); @@ -6471,6 +6598,12 @@ namespace Slang auto type = getFuncType(session, funcDeclRef); return QualType(type); } + else if (auto constraintDeclRef = declRef.As()) + { + auto type = DeclRefType::Create(session, constraintDeclRef); + *outTypeResult = type; + return QualType(getTypeType(type)); + } if( sink ) { sink->diagnose(declRef, Diagnostics::unimplemented, "cannot form reference to this kind of declaration"); diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 2627e1f37..54788e33a 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -1195,6 +1195,11 @@ struct EmitVisitor EmitDeclarator(declarator); } + void visitThisType(ThisType* type, TypeEmitArg const&) + { + return; + } + void visitDeclRefType(DeclRefType* declRefType, TypeEmitArg const& arg) { auto declarator = arg.declarator; diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 6099df1ed..7a3e9356a 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -881,6 +881,11 @@ struct ValLoweringVisitor : ValVisitor LoweredValInfo lowerFuncDecl(FunctionDeclBase* decl) { + if (decl->getName()->text == "test") + printf("break"); // Collect the parameter lists we will use for our new function. ParameterLists parameterLists; collectParameterLists(decl, ¶meterLists, kParameterListCollectMode_Default); diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index b8696df47..bdd041f71 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -765,6 +765,10 @@ struct LoweringVisitor loweredDeclRef.As()); } + RefPtr visitThisType(ThisType* type) + { + return type; + } RefPtr visitNamedExpressionType(NamedExpressionType* type) { diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index f1d1d6ba2..602a929b2 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -300,6 +300,7 @@ int CompileRequest::executeActionsInner() // Generate initial IR for all the translation // units, if we are in a mode where IR is called for. generateIR(); + if (mSink.GetErrorCount() != 0) return 1; diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis index 7e6fd3753..357251dcd 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -35,4 +35,25 @@ {{name={(char*)((*name).text.buffer.pointer+1), s} loc={loc.raw}}} + + + {{{op}}} + + op + argCount + + argCount + (IRUse*)(this + 1) + + + + + + + firstInst + (Slang::IRInst*)next + this + + + \ No newline at end of file diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index a3a5fdcb6..2f3368f4c 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -376,6 +376,85 @@ void Type::accept(IValVisitor* visitor, void* extra) (int)(typeid(this).hash_code())); } + // ThisType + + String ThisType::ToString() + { + return ""; + } + + int ThisType::GetHashCode() + { + return 0; + } + + bool ThisType::EqualsImpl(Type * type) + { + return true; + } + + Type* ThisType::CreateCanonicalType() + { + // A declaration reference is already canonical + return this; + } + + RefPtr ThisType::SubstituteImpl(Substitutions* subst, int* ioDiff) + { + while (subst) + { + if (auto thisTypeSubst = dynamic_cast(subst)) + { + return thisTypeSubst->sourceType; + } + subst = subst->outer; + } + return this; + } + + // MemberType + /* + String MemberType::ToString() + { + return objectType->ToString() + "::" + declRef.toString(); + } + + int MemberType::GetHashCode() + { + return combineHash(objectType->GetHashCode(), declRef.GetHashCode()); + } + + bool MemberType::EqualsImpl(Type * type) + { + if (auto memberType = dynamic_cast(type)) + return objectType->Equals(memberType->objectType.Ptr()) && declRef.Equals(memberType->declRef); + return false; + } + + Type* MemberType::CreateCanonicalType() + { + if (auto declRefType = objectType->As()) + { + if (auto aggDeclRef = declRefType->declRef.As()) + { + Decl* targetDecl = nullptr; + if (aggDeclRef.getDecl()->memberDictionary.TryGetValue(declRef.getDecl()->nameAndLoc.name, targetDecl)) + { + if (auto typeDefDecl = dynamic_cast(targetDecl)) + return typeDefDecl->type.type; + else + return DeclRefType::Create(getSession(), DeclRef(targetDecl, aggDeclRef.substitutions)); + } + } + } + return this; + } + + RefPtr MemberType::SubstituteImpl(Substitutions* subst, int* ioDiff) + { + return this; + } + */ // DeclRefType String DeclRefType::ToString() @@ -451,16 +530,21 @@ void Type::accept(IValVisitor* visitor, void* extra) // we want to replace it with the actual associated type else if (auto assocTypeDecl = dynamic_cast(declRef.getDecl())) { - // search for a substitution that might apply to us - for (auto s = subst; s; s = s->outer.Ptr()) + auto newSubst = declRef.substitutions->SubstituteImpl(subst, ioDiff); + if (auto thisTypeSubst = newSubst.As()) { - if (auto thisTypeSubst = dynamic_cast(s)) + if (thisTypeSubst->sourceType) { if (auto aggTypeDeclRef = thisTypeSubst->sourceType.As()->declRef.As()) { Decl * targetType = nullptr; if (aggTypeDeclRef.getDecl()->memberDictionary.TryGetValue(assocTypeDecl->getName(), targetType)) - return DeclRefType::Create(this->getSession(), DeclRef(targetType, aggTypeDeclRef.substitutions)); + { + if (auto typeDefDecl = dynamic_cast(targetType)) + return typeDefDecl->type.type; + else + return DeclRefType::Create(getSession(), DeclRef(targetType, aggTypeDeclRef.substitutions)); + } } } } @@ -1142,9 +1226,27 @@ void Type::accept(IValVisitor* visitor, void* extra) if (!this) return nullptr; int diff = 0; - auto outerSubst = outer->SubstituteImpl(subst, &diff); - - auto newSourceType = sourceType->SubstituteImpl(subst, ioDiff); + RefPtr outerSubst; + if (outer) + outerSubst = outer->SubstituteImpl(subst, &diff); + RefPtr newSourceType; + if (sourceType) + newSourceType = sourceType->SubstituteImpl(subst, &diff); + else + { + // this_type is a free variable, use this_type from subst + auto psubst = subst; + while (psubst) + { + if (auto pthisSubst = dynamic_cast(subst)) + { + diff++; + newSourceType = pthisSubst->sourceType; + break; + } + psubst = psubst->outer; + } + } if (!diff) return this; (*ioDiff)++; @@ -1162,7 +1264,9 @@ void Type::accept(IValVisitor* visitor, void* extra) auto thisSubst = dynamic_cast(subst); if (!thisSubst) return false; - if (!thisSubst->sourceType->EqualsVal(sourceType)) + if (!sourceType && thisSubst->sourceType || sourceType && !thisSubst->sourceType) + return false; + if (thisSubst->sourceType && !thisSubst->sourceType->EqualsVal(sourceType)) return false; if (!outer->Equals(subst->outer.Ptr())) return false; diff --git a/source/slang/syntax.h b/source/slang/syntax.h index 0b5a38631..cf75b5624 100644 --- a/source/slang/syntax.h +++ b/source/slang/syntax.h @@ -439,6 +439,7 @@ namespace Slang // Apply substitutions to this declaration reference DeclRefBase SubstituteImpl(Substitutions* subst, int* ioDiff); + // Check if this is an equivalent declaration reference to another bool Equals(DeclRefBase const& declRef) const; bool operator == (const DeclRefBase& other) const @@ -1154,7 +1155,7 @@ namespace Slang RefPtr createDefaultSubstitutions( Session* session, Decl* decl); - + } // namespace Slang #endif \ No newline at end of file diff --git a/source/slang/type-defs.h b/source/slang/type-defs.h index 60f519c82..7eda5b5ce 100644 --- a/source/slang/type-defs.h +++ b/source/slang/type-defs.h @@ -55,6 +55,38 @@ protected: ) END_SYNTAX_CLASS() +SYNTAX_CLASS(ThisType, Type) +RAW( + virtual String ToString() override; + virtual RefPtr SubstituteImpl(Substitutions* subst, int* ioDiff) override; + + ThisType() + {} + protected: + virtual int GetHashCode() override; + virtual bool EqualsImpl(Type * type) override; + virtual Type* CreateCanonicalType() override; + ) +END_SYNTAX_CLASS() + +/* +SYNTAX_CLASS(MemberType, Type) + FIELD(RefPtr, objectType) + DECL_FIELD(DeclRef, declRef) + RAW( + virtual String ToString() override; + virtual RefPtr SubstituteImpl(Substitutions* subst, int* ioDiff) override; + + MemberType() + {} + protected: + virtual int GetHashCode() override; + virtual bool EqualsImpl(Type * type) override; + virtual Type* CreateCanonicalType() override; + ) +END_SYNTAX_CLASS() +*/ + // A type that takes the form of a reference to some declaration SYNTAX_CLASS(DeclRefType, Type) DECL_FIELD(DeclRef, declRef) -- cgit v1.2.3