diff options
28 files changed, 942 insertions, 295 deletions
diff --git a/source/core/text-io.cpp b/source/core/text-io.cpp index ec41b8d7d..d0d0a3cc6 100644 --- a/source/core/text-io.cpp +++ b/source/core/text-io.cpp @@ -194,6 +194,17 @@ namespace Slang this->encoding = determinedEncoding; } + bool HasNullBytes(char * str, int len) + { + bool hasSeenNull = false; + for (int i = 0; i < len - 1; i++) + if (str[i] == 0) + hasSeenNull = true; + else if (hasSeenNull) + return true; + return false; + } + Encoding * StreamReader::DetermineEncoding() { if (buffer.Count() >= 3 && (unsigned char)(buffer[0]) == 0xEF && (unsigned char)(buffer[1]) == 0xBB && (unsigned char)(buffer[2]) == 0xBF) @@ -213,19 +224,11 @@ namespace Slang } else { -#ifdef _WIN32 - int flag = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_ASCII16; - int rs = IsTextUnicode(buffer.Buffer(), (int) buffer.Count(), &flag); - if (rs) - { - if (flag & (IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS)) - return Encoding::UTF16; - else if (flag & (IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS)) - return Encoding::UTF16Reversed; - else if (flag & IS_TEXT_UNICODE_ASCII16) - return Encoding::UTF8; - } -#endif + // find null bytes + if (HasNullBytes(buffer.Buffer(), (int)buffer.Count())) + { + return Encoding::UTF16; + } return Encoding::UTF8; } } @@ -233,6 +236,7 @@ namespace Slang void StreamReader::ReadBuffer() { buffer.SetSize(4096); + memset(buffer.Buffer(), 0, buffer.Count() * sizeof(buffer[0])); auto len = stream->Read(buffer.Buffer(), buffer.Count()); buffer.SetSize((int)len); ptr = 0; 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; diff --git a/source/slang/decl-defs.h b/source/slang/decl-defs.h index c96fe6d09..9c010d156 100644 --- a/source/slang/decl-defs.h +++ b/source/slang/decl-defs.h @@ -122,6 +122,10 @@ SYNTAX_CLASS(TypeDefDecl, SimpleTypeDecl) SYNTAX_FIELD(TypeExp, type) END_SYNTAX_CLASS() +// An 'assoctype' declaration, it is a container of inheritance clauses +SYNTAX_CLASS(AssocTypeDecl, AggTypeDecl) +END_SYNTAX_CLASS() + // A scope for local declarations (e.g., as part of a statement) SIMPLE_SYNTAX_CLASS(ScopeDecl, ContainerDecl) diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index cc7db7eb4..52f5d48a0 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -191,83 +191,10 @@ DIAGNOSTIC(30035, Error, componentOverloadTypeMismatch, "'$0': type of overloade DIAGNOSTIC(30041, Error, bitOperationNonIntegral, "bit operation: operand must be integral type.") DIAGNOSTIC(30047, Error, argumentExpectedLValue, "argument passed to parameter '$0' must be l-value.") DIAGNOSTIC(30051, Error, invalidValueForArgument, "invalid value for argument '$0'") -DIAGNOSTIC(30052, Error, ordinaryFunctionAsModuleArgument, "ordinary functions not allowed as argument to function-typed module parameter.") -DIAGNOSTIC(30079, Error, selectPrdicateTypeMismatch, "selector must evaluate to bool."); -DIAGNOSTIC(30080, Error, selectValuesTypeMismatch, "the two value expressions in a select clause must have same type."); -DIAGNOSTIC(31040, Error, undefinedTypeName, "undefined type name: '$0'.") -DIAGNOSTIC(32013, Error, circularReferenceNotAllowed, "'$0': circular reference is not allowed."); -DIAGNOSTIC(32014, Error, shaderDoesProvideRequirement, "shader '$0' does not provide '$1' as required by '$2'.") -DIAGNOSTIC(32015, Error, argumentNotAvilableInWorld, "argument '$0' is not available in world '$1' as required by '$2'.") -DIAGNOSTIC(32015, Error, componentNotAvilableInWorld, "component '$0' is not available in world '$1' as required by '$2'.") -DIAGNOSTIC(32047, Error, firstArgumentToImportNotComponent, "first argument of an import operator call does not resolve to a component."); -DIAGNOSTIC(32051, Error, componentTypeNotWhatPipelineRequires, "component '$0' has type '$1', but pipeline '$2' requires it to be '$3'.") -DIAGNOSTIC(32052, Error, shaderDoesNotDefineComponentAsRequiredByPipeline, "shader '$0' does not define '$1' as required by pipeline '$2''.") -DIAGNOSTIC(33001, Error, worldNameAlreadyDefined, "world '$0' is already defined.") -DIAGNOSTIC(33002, Error, explicitPipelineSpecificationRequiredForShader, "explicit pipeline specification required for shader '$0' because multiple pipelines are defined in current context.") -DIAGNOSTIC(33003, Error, cannotDefineComponentsInAPipeline, "cannot define components in a pipeline.") -DIAGNOSTIC(33004, Error, undefinedWorldName, "undefined world name '$0'.") -DIAGNOSTIC(33005, Error, abstractWorldAsTargetOfImport, "abstract world cannot appear as target as an import operator.") - -// Note(tfoley): This is a duplicate of 33004 above. -DIAGNOSTIC(33006, Error, undefinedWorldName2, "undefined world name '$0'.") - -DIAGNOSTIC(33007, Error, importOperatorCircularity, "import operator '$0' creates a circular dependency between world '$1' and '$2'") -DIAGNOSTIC(33009, Error, parametersOnlyAllowedInModules, "parameters can only be defined in modules.") -DIAGNOSTIC(33010, Error, undefinedPipelineName, "pipeline '$0' is undefined.") -DIAGNOSTIC(33011, Error, shaderCircularity, "shader '$0' involves circular reference.") -DIAGNOSTIC(33012, Error, worldIsNotDefinedInPipeline, "'$0' is not a defined world in '$1'.") -DIAGNOSTIC(33013, Error, abstractWorldCannotAppearWithOthers, "abstract world cannot appear with other worlds.") -DIAGNOSTIC(33014, Error, nonAbstractComponentMustHaveImplementation, "non-abstract component must have an implementation.") -DIAGNOSTIC(33016, Error, usingInComponentDefinition, "'using': importing not allowed in component definition.") -DIAGNOSTIC(33018, Error, nameAlreadyDefined, "'$0' is already defined.") -DIAGNOSTIC(33018, Error, shaderAlreadyDefined, "shader '$0' has already been defined.") -DIAGNOSTIC(33019, Error, componentMarkedExportMustHaveWorld, "component '$0': definition marked as 'export' must have an explicitly specified world.") -DIAGNOSTIC(33020, Error, componentIsAlreadyDefined, "'$0' is already defined.") -DIAGNOSTIC(33020, Error, componentIsAlreadyDefinedInThatWorld, "'$0' is already defined at '$1'.") -DIAGNOSTIC(33021, Error, inconsistentSignatureForComponent, "'$0': inconsistent signature.") -DIAGNOSTIC(33022, Error, nameAlreadyDefinedInCurrentScope, "'$0' is already defined in current scope.") -DIAGNOSTIC(33022, Error, parameterNameConflictsWithExistingDefinition, "'$0': parameter name conflicts with existing definition.") -DIAGNOSTIC(33023, Error, parameterOfModuleIsUnassigned, "parameter '$0' of module '$1' is unassigned.") -DIAGNOSTIC(33027, Error, argumentTypeDoesNotMatchParameterType, "argument type ($0) does not match parameter type ($1)") -DIAGNOSTIC(33028, Error, nameIsNotAParameterOfCallee, "'$0' is not a parameter of '$1'.") -DIAGNOSTIC(33029, Error, requirementsClashWithPreviousDef, "'$0': requirement clash with previous definition.") -DIAGNOSTIC(33030, Error, positionArgumentAfterNamed, "positional argument cannot appear after a named argument.") -DIAGNOSTIC(33032, Error, functionRedefinition, "'$0': function redefinition.") -DIAGNOSTIC(33034, Error, recordTypeVariableInImportOperator, "cannot declare a record-typed variable in an import operator.") -DIAGNOSTIC(33037, Error, componetMarkedExportCannotHaveParameters, "component '$0': definition marked as 'export' cannot have parameters.") -DIAGNOSTIC(33039, Error, componentInInputWorldCantHaveCode, "'$0': no code allowed for component defined in input world.") -DIAGNOSTIC(33040, Error, requireWithComputation, "'require': cannot define computation on component requirements.") -DIAGNOSTIC(33042, Error, paramWithComputation, "'param': cannot define computation on parameters.") -DIAGNOSTIC(33041, Error, pipelineOfModuleIncompatibleWithPipelineOfShader, "pipeline '$0' targeted by module '$1' is incompatible with pipeline '$2' targeted by shader '$3'.") DIAGNOSTIC(33070, Error, expectedFunction, "expression preceding parenthesis of apparent call must have function type.") -DIAGNOSTIC(33071, Error, importOperatorCalledFromAutoPlacedComponent, "cannot call an import operator from an auto-placed component '$0'. try qualify the component with explicit worlds.") -DIAGNOSTIC(33072, Error, noApplicableImportOperator, "'$0' is an import operator defined in pipeline '$1', but none of the import operator overloads converting to world '$2' matches argument list ($3).") -DIAGNOSTIC(33073, Error, importOperatorCalledFromMultiWorldComponent, "cannot call an import operator from a multi-world component definition. consider qualify the component with only one explicit world.") -DIAGNOSTIC(33080, Error, componentTypeDoesNotMatchInterface, "'$0': component type does not match definition in interface '$1'.") -DIAGNOSTIC(33081, Error, shaderDidNotDefineComponentFunction, "shader '$0' did not define component function $1 as required by interface '$2'.") -DIAGNOSTIC(33082, Error, shaderDidNotDefineComponent, "shader '$0' did not define component '$1' as required by interface '$2'.") -DIAGNOSTIC(33083, Error, interfaceImplMustBePublic, "'$0': component fulfilling interface '$1' must be declared as 'public'.") -DIAGNOSTIC(33084, Error, defaultParamNotAllowedInInterface, "'$0': default parameter value not allowed in interface definition.") - -DIAGNOSTIC(33100, Error, componentCantBeComputedAtWorldBecauseDependentNotAvailable, "'$0' cannot be computed at '$1' because the dependent component '$2' is not accessible.") -DIAGNOSTIC(33101, Warning, worldIsNotAValidChoiceForKey, "'$0' is not a valid choice for '$1'.") -DIAGNOSTIC(33102, Error, componentDefinitionCircularity, "component definition '$0' involves circular reference.") -DIAGNOSTIC(34024, Error, componentAlreadyDefinedWhenCompiling, "component named '$0' is already defined when compiling '$1'.") -DIAGNOSTIC(34025, Error, globalComponentConflictWithPreviousDeclaration, "'$0': global component conflicts with previous declaration.") -DIAGNOSTIC(34026, Warning, componentIsAlreadyDefinedUseRequire, "'$0': component is already defined when compiling shader '$1'. use 'require' to declare it as a parameter.") -DIAGNOSTIC(34062, Error, cylicReference, "cyclic reference: $0"); -DIAGNOSTIC(34064, Error, noApplicableImplicitImportOperator, "cannot find import operator to import component '$0' to world '$1' when compiling '$2'.") -DIAGNOSTIC(34065, Error, resourceTypeMustBeParamOrRequire, "'$0': resource typed component must be declared as 'param' or 'require'."); -DIAGNOSTIC(34066, Error, cannotDefineComputationOnResourceType, "'$0': cannot define computation on resource typed component."); - -DIAGNOSTIC(35001, Error, fragDepthAttributeCanOnlyApplyToOutput, "FragDepth attribute can only apply to an output component."); -DIAGNOSTIC(35002, Error, fragDepthAttributeCanOnlyApplyToFloatComponent, "FragDepth attribute can only apply to a float component."); - - -DIAGNOSTIC(36001, Error, insufficientTemplateShaderArguments, "instantiating template shader '$0': insufficient arguments."); -DIAGNOSTIC(36002, Error, tooManyTemplateShaderArguments, "instantiating template shader '$0': too many arguments."); -DIAGNOSTIC(36003, Error, templateShaderArgumentIsNotDefined, "'$0' provided as template shader argument to '$1' is not a defined module."); -DIAGNOSTIC(36004, Error, templateShaderArgumentDidNotImplementRequiredInterface, "module '$0' provided as template shader argument to '$1' did not implement required interface '$2'."); + +// 303xx: interfaces and associated types +DIAGNOSTIC(30300, Error, assocTypeInInterfaceOnly, "'associatedtype' can only be defined in an 'interface'.") // TODO: need to assign numbers to all these extra diagnostics... diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 336d73abe..056454845 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -395,8 +395,7 @@ struct EmitVisitor void emitRawTextSpan(char const* textBegin, char const* textEnd) { // TODO(tfoley): Need to make "corelib" not use `int` for pointer-sized things... - auto len = int(textEnd - textBegin); - + auto len = textEnd - textBegin; context->shared->sb.Append(textBegin, len); } @@ -1039,7 +1038,6 @@ struct EmitVisitor UNEXPECTED(PtrType); #undef UNEXPECTED - void visitNamedExpressionType(NamedExpressionType* type, TypeEmitArg const& arg) { // Named types are valid for GLSL @@ -2917,7 +2915,7 @@ struct EmitVisitor return; } - Substitutions* subst = declRef.substitutions.Ptr(); + GenericSubstitution* subst = declRef.substitutions.As<GenericSubstitution>().Ptr(); if (!subst) return; @@ -3009,6 +3007,12 @@ struct EmitVisitor Emit(";\n"); } + void visitAssocTypeDecl(AssocTypeDecl * /*assocType*/, DeclEmitArg const&) + { + SLANG_UNREACHABLE("visitAssocTypeDecl in EmitVisitor"); + } + + void visitImportDecl(ImportDecl* decl, DeclEmitArg const&) { // When in "rewriter" mode, we need to emit the code of the imported diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index 8127fb70f..f70ab46ff 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -346,10 +346,9 @@ struct IRBuilder IRValue* getBoolValue(bool value); IRValue* getIntValue(IRType* type, IRIntegerValue value); IRValue* getFloatValue(IRType* type, IRFloatingPointValue value); - IRValue* getDeclRefVal( DeclRefBase const& declRef); - + IRValue* getTypeVal(IRType* type); // create an IR value that represents a type IRValue* emitSpecializeInst( IRType* type, IRValue* genericVal, diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index ca82b21e7..ab961a159 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -178,27 +178,27 @@ namespace Slang // // Add an instruction to a specific parent - void IRBuilder::addInst(IRBlock* block, IRInst* inst) + void IRBuilder::addInst(IRBlock* pblock, IRInst* inst) { - inst->parent = block; + inst->parent = pblock; - if (!block->firstInst) + if (!pblock->firstInst) { inst->prev = nullptr; inst->next = nullptr; - block->firstInst = inst; - block->lastInst = inst; + pblock->firstInst = inst; + pblock->lastInst = inst; } else { - auto prev = block->lastInst; + auto prev = pblock->lastInst; inst->prev = prev; inst->next = nullptr; prev->next = inst; - block->lastInst = inst; + pblock->lastInst = inst; } } @@ -560,6 +560,18 @@ namespace Slang return irValue; } + IRValue * IRBuilder::getTypeVal(IRType * type) + { + auto irValue = createValue<IRValue>( + this, + kIROp_TypeType, + nullptr); + irValue->type = type; + if (auto typetype = dynamic_cast<TypeType*>(type)) + irValue->type = typetype->type; + return irValue; + } + IRValue* IRBuilder::emitSpecializeInst( Type* type, IRValue* genericVal, @@ -620,7 +632,7 @@ namespace Slang IRInst* IRBuilder::emitCallInst( IRType* type, - IRValue* func, + IRValue* pFunc, UInt argCount, IRValue* const* args) { @@ -629,7 +641,7 @@ namespace Slang kIROp_Call, type, 1, - &func, + &pFunc, argCount, args); addInst(inst); @@ -1531,7 +1543,7 @@ namespace Slang if(genericParentDeclRef) { - auto subst = declRef.substitutions; + auto subst = declRef.substitutions.As<GenericSubstitution>(); if( !subst || subst->genericDecl != genericParentDeclRef.getDecl() ) { // No actual substitutions in place here @@ -3058,7 +3070,12 @@ namespace Slang return builder->getDeclRefVal(declRef); } break; - + case kIROp_TypeType: + { + IRValue* od = (IRValue*)originalValue; + return builder->getTypeVal(od->type); + } + break; default: SLANG_UNEXPECTED("no value registered for IR value"); UNREACHABLE_RETURN(nullptr); @@ -3093,18 +3110,27 @@ namespace Slang { if (!subst) return nullptr; + if (auto genSubst = dynamic_cast<GenericSubstitution*>(subst)) + { + RefPtr<GenericSubstitution> newSubst = new GenericSubstitution(); + newSubst->outer = cloneSubstitutions(context, subst->outer); + newSubst->genericDecl = genSubst->genericDecl; - RefPtr<Substitutions> newSubst = new Substitutions(); - newSubst->outer = cloneSubstitutions(context, subst->outer); - newSubst->genericDecl = subst->genericDecl; - - for (auto arg : subst->args) + for (auto arg : genSubst->args) + { + auto newArg = cloneSubstitutionArg(context, arg); + newSubst->args.Add(arg); + } + return newSubst; + } + else if (auto thisSubst = dynamic_cast<ThisTypeSubstitution*>(subst)) { - auto newArg = cloneSubstitutionArg(context, arg); - newSubst->args.Add(arg); + RefPtr<ThisTypeSubstitution> newSubst = new ThisTypeSubstitution(); + newSubst->sourceType = thisSubst->sourceType; + newSubst->outer = cloneSubstitutions(context, subst->outer); + return newSubst; } - - return newSubst; + return nullptr; } DeclRef<Decl> IRSpecContext::maybeCloneDeclRef(DeclRef<Decl> const& declRef) @@ -3738,7 +3764,8 @@ namespace Slang IRGenericSpecContext* context, DeclRef<Decl> declRef) { - auto subst = context->subst; + auto subst = context->subst.As<GenericSubstitution>(); + SLANG_ASSERT(subst); auto genericDecl = subst->genericDecl; UInt orinaryParamCount = 0; @@ -3788,12 +3815,13 @@ namespace Slang { auto declRefVal = (IRDeclRef*) originalVal; auto declRef = declRefVal->declRef; - + auto genSubst = subst.As<GenericSubstitution>(); + SLANG_ASSERT(genSubst); // We may have a direct reference to one of the parameters // of the generic we are specializing, and in that case // we nee to translate it over to the equiavalent of // the `Val` we have been given. - if(declRef.getDecl()->ParentDecl == subst->genericDecl) + if(declRef.getDecl()->ParentDecl == genSubst->genericDecl) { return getSubstValue(this, declRef); } @@ -3848,9 +3876,10 @@ namespace Slang // using a different overload of a target-specific function, // so we need to create a dummy substitution here, to make // sure it used the correct generic. - RefPtr<Substitutions> newSubst = new Substitutions(); + RefPtr<GenericSubstitution> newSubst = new GenericSubstitution(); newSubst->genericDecl = genericFunc->genericDecl; - newSubst->args = specDeclRef.substitutions->args; + auto specDeclRefSubst = specDeclRef.substitutions.As<GenericSubstitution>(); + newSubst->args = specDeclRefSubst->args; IRGenericSpecContext context; context.shared = sharedContext; diff --git a/source/slang/lookup.cpp b/source/slang/lookup.cpp index c0cb657c4..b01732362 100644 --- a/source/slang/lookup.cpp +++ b/source/slang/lookup.cpp @@ -410,7 +410,27 @@ void lookUpMemberImpl( if (auto declRefType = type->As<DeclRefType>()) { auto declRef = declRefType->declRef; - if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>()) + if (auto assocTypeDeclRef = declRef.As<AssocTypeDecl>()) + { + for (auto constraintDeclRef : getMembersOfType<GenericTypeConstraintDecl>(assocTypeDeclRef)) + { + // The super-type in the constraint (e.g., `Foo` in `T : Foo`) + // will tell us a type we should use for lookup. + auto bound = GetSup(constraintDeclRef); + + // Go ahead and use the target type, with an appropriate breadcrumb + // to indicate that we indirected through a type constraint. + + BreadcrumbInfo breadcrumb; + breadcrumb.prev = inBreadcrumbs; + breadcrumb.kind = LookupResultItem::Breadcrumb::Kind::Constraint; + breadcrumb.declRef = constraintDeclRef; + + // TODO: Need to consider case where this might recurse infinitely. + lookUpMemberImpl(session, semantics, name, bound, ioResult, &breadcrumb); + } + } + else if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>()) { LookupRequest request; request.semantics = semantics; @@ -452,7 +472,9 @@ void lookUpMemberImpl( lookUpMemberImpl(session, semantics, name, bound, ioResult, &breadcrumb); } } + } + } LookupResult lookUpMember( diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index a659326e4..2672c5698 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -871,9 +871,12 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower auto subs = declRef.substitutions; while(subs) { - for(auto aa : subs->args) + if (auto genSubst = subs.As<GenericSubstitution>()) { - (*ioArgs).Add(getSimpleVal(context, lowerVal(context, aa))); + for (auto aa : genSubst->args) + { + (*ioArgs).Add(getSimpleVal(context, lowerVal(context, aa))); + } } subs = subs->outer; } @@ -2060,6 +2063,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> SLANG_UNIMPLEMENTED_X("decl catch-all"); } + LoweredValInfo visitTypeDefDecl(TypeDefDecl * decl) + { + return LoweredValInfo::simple(context->irBuilder->getTypeVal(decl->type.type)); + } + LoweredValInfo visitGenericTypeParamDecl(GenericTypeParamDecl* /*decl*/) { return LoweredValInfo(); @@ -2303,9 +2311,13 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> ensureDecl(context, inheritanceDecl); } - // For now, we don't have an IR-level representation - // for the type itself. - return LoweredValInfo(); + // TODO: we currently store a Decl* in the witness table, which causes this function + // being invoked to translate the witness table entry into an IRValue. + // We should really allow a witness table entry to represent a type and not having to + // construct the type here. The current implementation will not work when the struct type + // is defined in a generic parent (we lose the environmental substitutions). + return LoweredValInfo::simple(context->irBuilder->getTypeVal(DeclRefType::Create(context->getSession(), + DeclRef<Decl>(decl, nullptr)))); } @@ -3029,24 +3041,33 @@ RefPtr<Substitutions> lowerSubstitutions( { if(!subst) return nullptr; + RefPtr<Substitutions> result; + if (auto genSubst = dynamic_cast<GenericSubstitution*>(subst)) + { + RefPtr<GenericSubstitution> newSubst = new GenericSubstitution(); + newSubst->genericDecl = genSubst->genericDecl; + + for (auto arg : genSubst->args) + { + auto newArg = lowerSubstitutionArg(context, arg); + newSubst->args.Add(newArg); + } - RefPtr<Substitutions> newSubst = new Substitutions(); + result = newSubst; + } + else if (auto thisSubst = dynamic_cast<ThisTypeSubstitution*>(subst)) + { + RefPtr<ThisTypeSubstitution> newSubst = new ThisTypeSubstitution(); + newSubst->sourceType = lowerSubstitutionArg(context, thisSubst->sourceType); + result = newSubst; + } if (subst->outer) { - newSubst->outer = lowerSubstitutions( + result->outer = lowerSubstitutions( context, subst->outer); } - - newSubst->genericDecl = subst->genericDecl; - - for (auto arg : subst->args) - { - auto newArg = lowerSubstitutionArg(context, arg); - newSubst->args.Add(newArg); - } - - return newSubst; + return result; } LoweredValInfo emitDeclRef( @@ -3059,7 +3080,7 @@ LoweredValInfo emitDeclRef( // If this declaration reference doesn't involve any specializations, // then we are done at this point. - if(!declRef.substitutions) + if(!hasGenericSubstitutions(declRef.substitutions)) return loweredDecl; auto val = getSimpleVal(context, loweredDecl); diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index 73854a5c7..44ad5c272 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -2554,14 +2554,24 @@ struct LoweringVisitor Substitutions* inSubstitutions) { if (!inSubstitutions) return nullptr; - - RefPtr<Substitutions> result = new Substitutions(); - result->genericDecl = translateDeclRef(inSubstitutions->genericDecl).As<GenericDecl>(); - for (auto arg : inSubstitutions->args) + if (auto genSubst = dynamic_cast<GenericSubstitution*>(inSubstitutions)) + { + RefPtr<GenericSubstitution> result = new GenericSubstitution(); + result->genericDecl = translateDeclRef(genSubst->genericDecl).As<GenericDecl>(); + for (auto arg : genSubst->args) + { + result->args.Add(translateVal(arg)); + } + return result; + } + else if (auto thisSubst = dynamic_cast<ThisTypeSubstitution*>(inSubstitutions)) { - result->args.Add(translateVal(arg)); + RefPtr<ThisTypeSubstitution> result = new ThisTypeSubstitution(); + if (result->sourceType) + result->sourceType = translateVal(result->sourceType); + return result; } - return result; + return nullptr; } static Decl* getModifiedDecl(Decl* decl) @@ -2718,7 +2728,11 @@ struct LoweringVisitor RefPtr<VarLayout> tryToFindLayout( Decl* decl) { - auto loweredParent = translateDeclRef(decl->ParentDecl); + RefPtr<Decl> loweredParent; + if (auto genericParentDecl = decl->ParentDecl->As<GenericDecl>()) + loweredParent = translateDeclRef(genericParentDecl->ParentDecl); + else + loweredParent = translateDeclRef(decl->ParentDecl); if (loweredParent) { auto layoutMod = loweredParent->FindModifier<ComputedLayoutModifier>(); @@ -2820,6 +2834,13 @@ struct LoweringVisitor return LoweredDecl(); } + LoweredDecl visitAssocTypeDecl(AssocTypeDecl * /*assocType*/) + { + // not supported + SLANG_UNREACHABLE("visitAssocTypeDecl in LowerVisitor"); + UNREACHABLE_RETURN(LoweredDecl()); + } + LoweredDecl visitTypeDefDecl(TypeDefDecl* decl) { if (shared->target == CodeGenTarget::GLSL) @@ -3809,7 +3830,7 @@ struct LoweringVisitor "Vector").As<GenericDecl>(); auto vectorTypeDecl = vectorGenericDecl->inner; - auto substs = new Substitutions(); + auto substs = new GenericSubstitution(); substs->genericDecl = vectorGenericDecl.Ptr(); substs->args.Add(elementType); substs->args.Add(elementCount); diff --git a/source/slang/mangle.cpp b/source/slang/mangle.cpp index a690e5b74..b9fba6380 100644 --- a/source/slang/mangle.cpp +++ b/source/slang/mangle.cpp @@ -195,7 +195,7 @@ namespace Slang // There are two cases here: either we have specializations // in place for the parent generic declaration, or we don't. - auto subst = declRef.substitutions; + auto subst = declRef.substitutions.As<GenericSubstitution>(); if( subst && subst->genericDecl == parentGenericDeclRef.getDecl() ) { // This is the case where we *do* have substitutions. diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 8ec6f70ca..57956485a 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -1396,6 +1396,16 @@ namespace Slang return genericApp; } + static RefPtr<Expr> parseMemberType(Parser * parser, RefPtr<Expr> base) + { + RefPtr<MemberExpr> memberExpr = new MemberExpr(); + parser->ReadToken(TokenType::Dot); + parser->FillPosition(memberExpr.Ptr()); + memberExpr->BaseExpression = base; + memberExpr->name = expectIdentifier(parser).name; + return memberExpr; + } + // Parse option `[]` braces after a type expression, that indicate an array type static RefPtr<Expr> parsePostfixTypeSuffix( Parser* parser, @@ -1418,8 +1428,7 @@ namespace Slang return typeExpr; } - static TypeSpec - parseTypeSpec(Parser* parser) + static TypeSpec parseTypeSpec(Parser* parser) { TypeSpec typeSpec; @@ -1452,9 +1461,20 @@ namespace Slang RefPtr<Expr> typeExpr = basicType; - if (parser->LookAheadToken(TokenType::OpLess)) + bool shouldLoop = true; + while (shouldLoop) { - typeExpr = parseGenericApp(parser, typeExpr); + switch (peekTokenType(parser)) + { + case TokenType::OpLess: + typeExpr = parseGenericApp(parser, typeExpr); + break; + case TokenType::Dot: + typeExpr = parseMemberType(parser, typeExpr); + break; + default: + shouldLoop = false; + } } // GLSL allows `[]` directly in a type specifier @@ -2089,6 +2109,41 @@ namespace Slang } } + RefPtr<RefObject> ParseAssocType(Parser * parser, void *) + { + RefPtr<AssocTypeDecl> assocTypeDecl = new AssocTypeDecl(); + + auto nameToken = parser->ReadToken(TokenType::Identifier); + assocTypeDecl->nameAndLoc = NameLoc(nameToken); + assocTypeDecl->loc = nameToken.loc; + if (AdvanceIf(parser, TokenType::Colon)) + { + while (!parser->tokenReader.IsAtEnd()) + { + auto paramConstraint = new GenericTypeConstraintDecl(); + parser->FillPosition(paramConstraint); + + auto paramType = DeclRefType::Create( + parser->getSession(), + DeclRef<Decl>(assocTypeDecl, nullptr)); + + auto paramTypeExpr = new SharedTypeExpr(); + paramTypeExpr->loc = assocTypeDecl->loc; + paramTypeExpr->base.type = paramType; + paramTypeExpr->type = QualType(getTypeType(paramType)); + + paramConstraint->sub = TypeExp(paramTypeExpr); + paramConstraint->sup = parser->ParseTypeExp(); + + AddMember(assocTypeDecl, paramConstraint); + if (!AdvanceIf(parser, TokenType::Comma)) + break; + } + } + parser->ReadToken(TokenType::Semicolon); + return assocTypeDecl; + } + static RefPtr<RefObject> parseInterfaceDecl(Parser* parser, void* /*userData*/) { RefPtr<InterfaceDecl> decl = new InterfaceDecl(); @@ -4029,8 +4084,8 @@ namespace Slang // Add syntax for declaration keywords #define DECL(KEYWORD, CALLBACK) \ addBuiltinSyntax<Decl>(session, scope, #KEYWORD, &CALLBACK) - DECL(typedef, ParseTypeDef); + DECL(associatedtype,ParseAssocType); DECL(cbuffer, parseHLSLCBufferDecl); DECL(tbuffer, parseHLSLTBufferDecl); DECL(__generic, ParseGenericDecl); diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index ecee38777..1cda8e7d0 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..5bf8a1b09 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -35,4 +35,66 @@ <Type Name="Slang::NameLoc"> <DisplayString>{{name={(char*)((*name).text.buffer.pointer+1), s} loc={loc.raw}}}</DisplayString> </Type> + <Type Name="Slang::IRValue"> + <DisplayString>{{{op}}}</DisplayString> + <Expand> + <Item Name="[OpCode]">op</Item> + <Item Name="[Type]">type</Item> + <Item Name="[IRInst]">(Slang::IRInst*)this</Item> + <ExpandedItem Condition="op==kIROp_decl_ref">(Slang::IRDeclRef*)this</ExpandedItem> + <ExpandedItem Condition="op==kIROp_Func">(Slang::IRFunc*)this</ExpandedItem> + <ExpandedItem Condition="op==kIROp_Block">(Slang::IRBlock*)this</ExpandedItem> + <Item Name="====Uses====">"-------"</Item> + <LinkedListItems> + <HeadPointer>firstUse</HeadPointer> + <NextPointer>nextUse</NextPointer> + <ValueNode>usedValue</ValueNode> + </LinkedListItems> + + </Expand> + </Type> + <Type Name="Slang::IRUser"> + <DisplayString>{{{op}}}</DisplayString> + <Expand> + <Item Name="[OpCode]">op</Item> + <Item Name="[ArgCount]">argCount</Item> + <ArrayItems> + <Size>argCount</Size> + <ValuePointer>(IRUse*)(this + 1)</ValuePointer> + </ArrayItems> + </Expand> + </Type> + <Type Name="Slang::IRBlock"> + <Expand> + <LinkedListItems> + <HeadPointer>firstInst</HeadPointer> + <NextPointer>(Slang::IRInst*)next</NextPointer> + <ValueNode>this</ValueNode> + </LinkedListItems> + </Expand> + </Type> + <Type Name="Slang::IRFunc"> + <DisplayString>{{{mangledName}}}</DisplayString> + <Expand> + <Item Name="[Name]">mangledName</Item> + <Item Name="[ResultType]">(*(IRFuncType*)(type.pointer)).resultType</Item> + <Item Name="[ParameterTypes]">(*(IRFuncType*)(type.pointer)).paramTypes</Item> + <Item Name="[FirstBlock]">firstBlock</Item> + </Expand> + </Type> + + <Type Name="Slang::IRDeclRef"> + <DisplayString>{{IRDeclRef {declRef}}}</DisplayString> + <Expand> + <Item Name="[OpCode]">op</Item> + <ExpandedItem>declRef</ExpandedItem> + </Expand> + </Type> + <Type Name="Slang::IRUse"> + <DisplayString>{{IRUse {usedValue}}}</DisplayString> + <Expand> + <Item Name="[NextUse]">nextUse</Item> + <ExpandedItem>usedValue</ExpandedItem> + </Expand> + </Type> </AutoVisualizer>
\ No newline at end of file diff --git a/source/slang/syntax-base-defs.h b/source/slang/syntax-base-defs.h index 8a22a61d2..3c7e8c5ae 100644 --- a/source/slang/syntax-base-defs.h +++ b/source/slang/syntax-base-defs.h @@ -126,31 +126,44 @@ protected: ) END_SYNTAX_CLASS() + // A substitution represents a binding of certain // type-level variables to concrete argument values -SYNTAX_CLASS(Substitutions, RefObject) +ABSTRACT_SYNTAX_CLASS(Substitutions, RefObject) + + // Any further substitutions, relating to outer generic declarations + SYNTAX_FIELD(RefPtr<Substitutions>, outer) + + RAW( + // Apply a set of substitutions to the bindings in this substitution + virtual RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff) = 0; + // Check if these are equivalent substitutiosn to another set + virtual bool Equals(Substitutions* subst) = 0; + virtual bool operator == (const Substitutions & subst) = 0; + virtual int GetHashCode() const = 0; + ) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(GenericSubstitution, Substitutions) // The generic declaration that defines the // parametesr we are binding to arguments - DECL_FIELD(GenericDecl*, genericDecl) + DECL_FIELD(GenericDecl*, genericDecl) // The actual values of the arguments SYNTAX_FIELD(List<RefPtr<Val>>, args) - - // Any further substitutions, relating to outer generic declarations - SYNTAX_FIELD(RefPtr<Substitutions>, outer) - + RAW( // Apply a set of substitutions to the bindings in this substitution - RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff); + virtual RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff) override; // Check if these are equivalent substitutiosn to another set - bool Equals(Substitutions* subst); - bool operator == (const Substitutions & subst) + virtual bool Equals(Substitutions* subst) override; + virtual bool operator == (const Substitutions & subst) override { return Equals(const_cast<Substitutions*>(&subst)); } - int GetHashCode() const + virtual int GetHashCode() const override { int rs = 0; for (auto && v : args) @@ -163,6 +176,27 @@ SYNTAX_CLASS(Substitutions, RefObject) ) END_SYNTAX_CLASS() +SYNTAX_CLASS(ThisTypeSubstitution, Substitutions) + // The actual type that provides the lookup scope for an associated type + SYNTAX_FIELD(RefPtr<Val>, sourceType) + + RAW( + // Apply a set of substitutions to the bindings in this substitution + virtual RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff) override; + + // Check if these are equivalent substitutiosn to another set + virtual bool Equals(Substitutions* subst) override; + virtual bool operator == (const Substitutions & subst) override + { + return Equals(const_cast<Substitutions*>(&subst)); + } + virtual int GetHashCode() const override + { + return sourceType->GetHashCode(); + } + ) +END_SYNTAX_CLASS() + ABSTRACT_SYNTAX_CLASS(SyntaxNode, SyntaxNodeBase) END_SYNTAX_CLASS() diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index 149e0b811..9acdadad6 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -91,6 +91,8 @@ ABSTRACT_SYNTAX_CLASS(Modifier, SyntaxNodeBase); ABSTRACT_SYNTAX_CLASS(Expr, SyntaxNode); ABSTRACT_SYNTAX_CLASS(Substitutions, SyntaxNode); +ABSTRACT_SYNTAX_CLASS(GenericSubstitution, Substitutions); +ABSTRACT_SYNTAX_CLASS(ThisTypeSubstitution, Substitutions); #include "expr-defs.h" #include "decl-defs.h" @@ -98,8 +100,6 @@ ABSTRACT_SYNTAX_CLASS(Substitutions, SyntaxNode); #include "stmt-defs.h" #include "type-defs.h" #include "val-defs.h" - - #include "object-meta-end.h" bool SyntaxClassBase::isSubClassOfImpl(SyntaxClassBase const& super) const @@ -283,7 +283,7 @@ void Type::accept(IValVisitor* visitor, void* extra) this, "PtrType").As<GenericDecl>(); auto typeDecl = genericDecl->inner; - auto substitutions = new Substitutions(); + auto substitutions = new GenericSubstitution(); substitutions->genericDecl = genericDecl.Ptr(); substitutions->args.Add(valueType); @@ -414,38 +414,69 @@ void Type::accept(IValVisitor* visitor, void* extra) // search for a substitution that might apply to us for (auto s = subst; s; s = s->outer.Ptr()) { - // the generic decl associated with the substitution list must be - // the generic decl that declared this parameter - auto genericDecl = s->genericDecl; - if (genericDecl != genericTypeParamDecl->ParentDecl) - continue; - - int index = 0; - for (auto m : genericDecl->Members) + if (auto genericSubst = dynamic_cast<GenericSubstitution*>(s)) { - if (m.Ptr() == genericTypeParamDecl) - { - // We've found it, so return the corresponding specialization argument - (*ioDiff)++; - return s->args[index]; - } - else if(auto typeParam = m.As<GenericTypeParamDecl>()) - { - index++; - } - else if(auto valParam = m.As<GenericValueParamDecl>()) + // the generic decl associated with the substitution list must be + // the generic decl that declared this parameter + auto genericDecl = genericSubst->genericDecl; + if (genericDecl != genericTypeParamDecl->ParentDecl) + continue; + + int index = 0; + for (auto m : genericDecl->Members) { - index++; + if (m.Ptr() == genericTypeParamDecl) + { + // We've found it, so return the corresponding specialization argument + (*ioDiff)++; + return genericSubst->args[index]; + } + else if (auto typeParam = m.As<GenericTypeParamDecl>()) + { + index++; + } + else if (auto valParam = m.As<GenericValueParamDecl>()) + { + index++; + } + else + { + } } - else + } + + } + } + // the second case we care about is when this decl type refers to an associatedtype decl + // we want to replace it with the actual associated type + else if (auto assocTypeDecl = dynamic_cast<AssocTypeDecl*>(declRef.getDecl())) + { + auto thisSubst = getThisTypeSubst(declRef, false); + auto oldSubstSrc = thisSubst ? thisSubst->sourceType : nullptr; + bool restore = false; + if (thisSubst && thisSubst->sourceType.Ptr() == dynamic_cast<Val*>(this)) + thisSubst->sourceType = nullptr; + auto newSubst = declRef.substitutions->SubstituteImpl(subst, ioDiff); + if (restore) + thisSubst->sourceType = oldSubstSrc; + if (auto thisTypeSubst = newSubst.As<ThisTypeSubstitution>()) + { + if (thisTypeSubst->sourceType) + { + if (auto aggTypeDeclRef = thisTypeSubst->sourceType.As<DeclRefType>()->declRef.As<AggTypeDecl>()) { + Decl * targetType = nullptr; + if (aggTypeDeclRef.getDecl()->memberDictionary.TryGetValue(assocTypeDecl->getName(), targetType)) + { + if (auto typeDefDecl = dynamic_cast<TypeDefDecl*>(targetType)) + return typeDefDecl->type.type; + else + return DeclRefType::Create(getSession(), DeclRef<Decl>(targetType, aggTypeDeclRef.substitutions)); + } } } - } } - - int diff = 0; DeclRef<Decl> substDeclRef = declRef.SubstituteImpl(subst, &diff); @@ -486,10 +517,25 @@ void Type::accept(IValVisitor* visitor, void* extra) // we will construct a default specialization at the use // site if needed. - if( auto genericParent = declRef.GetParent().As<GenericDecl>() ) + if (auto genericParent = declRef.GetParent().As<GenericDecl>()) { auto subst = declRef.substitutions; - if( !subst || subst->genericDecl != genericParent.decl ) + // try find a substitution targeting this generic decl + bool substFound = false; + while (subst) + { + if (auto genSubst = dynamic_cast<GenericSubstitution*>(subst.Ptr())) + { + if (genSubst->genericDecl == genericParent.decl) + { + substFound = true; + break; + } + } + subst = subst->outer; + } + // we did not find an existing substituion, create a default one + if (!substFound) { declRef.substitutions = createDefaultSubstitutions( session, @@ -507,7 +553,7 @@ void Type::accept(IValVisitor* visitor, void* extra) } else if (auto magicMod = declRef.getDecl()->FindModifier<MagicTypeModifier>()) { - Substitutions* subst = declRef.substitutions.Ptr(); + GenericSubstitution* subst = declRef.substitutions.As<GenericSubstitution>().Ptr(); if (magicMod->name == "SamplerState") { @@ -972,24 +1018,24 @@ void Type::accept(IValVisitor* visitor, void* extra) Type* MatrixExpressionType::getElementType() { - return this->declRef.substitutions->args[0].As<Type>().Ptr(); + return this->declRef.substitutions.As<GenericSubstitution>()->args[0].As<Type>().Ptr(); } IntVal* MatrixExpressionType::getRowCount() { - return this->declRef.substitutions->args[1].As<IntVal>().Ptr(); + return this->declRef.substitutions.As<GenericSubstitution>()->args[1].As<IntVal>().Ptr(); } IntVal* MatrixExpressionType::getColumnCount() { - return this->declRef.substitutions->args[2].As<IntVal>().Ptr(); + return this->declRef.substitutions.As<GenericSubstitution>()->args[2].As<IntVal>().Ptr(); } // PtrTypeBase Type* PtrTypeBase::getValueType() { - return this->declRef.substitutions->args[0].As<Type>().Ptr(); + return this->declRef.substitutions.As<GenericSubstitution>()->args[0].As<Type>().Ptr(); } // GenericParamIntVal @@ -1018,31 +1064,34 @@ void Type::accept(IValVisitor* visitor, void* extra) // search for a substitution that might apply to us for (auto s = subst; s; s = s->outer.Ptr()) { - // the generic decl associated with the substitution list must be - // the generic decl that declared this parameter - auto genericDecl = s->genericDecl; - if (genericDecl != declRef.getDecl()->ParentDecl) - continue; - - int index = 0; - for (auto m : genericDecl->Members) + if (auto genSubst = dynamic_cast<GenericSubstitution*>(s)) { - if (m.Ptr() == declRef.getDecl()) - { - // We've found it, so return the corresponding specialization argument - (*ioDiff)++; - return s->args[index]; - } - else if(auto typeParam = m.As<GenericTypeParamDecl>()) - { - index++; - } - else if(auto valParam = m.As<GenericValueParamDecl>()) - { - index++; - } - else + // the generic decl associated with the substitution list must be + // the generic decl that declared this parameter + auto genericDecl = genSubst->genericDecl; + if (genericDecl != declRef.getDecl()->ParentDecl) + continue; + + int index = 0; + for (auto m : genericDecl->Members) { + if (m.Ptr() == declRef.getDecl()) + { + // We've found it, so return the corresponding specialization argument + (*ioDiff)++; + return genSubst->args[index]; + } + else if (auto typeParam = m.As<GenericTypeParamDecl>()) + { + index++; + } + else if (auto valParam = m.As<GenericValueParamDecl>()) + { + index++; + } + else + { + } } } } @@ -1053,12 +1102,12 @@ void Type::accept(IValVisitor* visitor, void* extra) // Substitutions - RefPtr<Substitutions> Substitutions::SubstituteImpl(Substitutions* subst, int* ioDiff) + RefPtr<Substitutions> GenericSubstitution::SubstituteImpl(Substitutions* subst, int* ioDiff) { if (!this) return nullptr; int diff = 0; - auto outerSubst = outer->SubstituteImpl(subst, &diff); + auto outerSubst = outer ? outer->SubstituteImpl(subst, &diff) : nullptr; List<RefPtr<Val>> substArgs; for (auto a : args) @@ -1069,35 +1118,85 @@ void Type::accept(IValVisitor* visitor, void* extra) if (!diff) return this; (*ioDiff)++; - auto substSubst = new Substitutions(); + auto substSubst = new GenericSubstitution(); substSubst->genericDecl = genericDecl; substSubst->args = substArgs; return substSubst; } - bool Substitutions::Equals(Substitutions* subst) + bool GenericSubstitution::Equals(Substitutions* subst) { // both must be NULL, or non-NULL if (!this || !subst) return !this && !subst; - - if (genericDecl != subst->genericDecl) + auto genericSubst = dynamic_cast<GenericSubstitution*>(subst); + if (!genericSubst) + return false; + if (genericDecl != genericSubst->genericDecl) return false; UInt argCount = args.Count(); - SLANG_RELEASE_ASSERT(args.Count() == subst->args.Count()); + SLANG_RELEASE_ASSERT(args.Count() == genericSubst->args.Count()); for (UInt aa = 0; aa < argCount; ++aa) { - if (!args[aa]->EqualsVal(subst->args[aa].Ptr())) + if (!args[aa]->EqualsVal(genericSubst->args[aa].Ptr())) return false; } + if (!outer) + return !subst->outer || subst->outer.As<ThisTypeSubstitution>(); + if (!outer->Equals(subst->outer.Ptr())) return false; return true; } + RefPtr<Substitutions> ThisTypeSubstitution::SubstituteImpl(Substitutions* subst, int* ioDiff) + { + if (!this) return nullptr; + + int diff = 0; + RefPtr<Substitutions> outerSubst; + if (outer) + outerSubst = outer->SubstituteImpl(subst, &diff); + RefPtr<Val> 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<ThisTypeSubstitution*>(subst)) + { + diff++; + newSourceType = pthisSubst->sourceType; + break; + } + psubst = psubst->outer; + } + } + if (!diff) return this; + + (*ioDiff)++; + auto substSubst = new ThisTypeSubstitution(); + substSubst->sourceType = newSourceType; + substSubst->outer = outerSubst; + return substSubst; + } + + bool ThisTypeSubstitution::Equals(Substitutions* subst) + { + if (!subst) + return true; + if (subst && dynamic_cast<ThisTypeSubstitution*>(subst)) + return true; + return false; + } + + // DeclRefBase @@ -1158,7 +1257,8 @@ void Type::accept(IValVisitor* visitor, void* extra) { if (decl != declRef.decl) return false; - + if (!substitutions) + return !declRef.substitutions || declRef.substitutions.As<ThisTypeSubstitution>(); if (!substitutions->Equals(declRef.substitutions.Ptr())) return false; @@ -1179,7 +1279,8 @@ void Type::accept(IValVisitor* visitor, void* extra) if (auto parentGeneric = dynamic_cast<GenericDecl*>(parentDecl)) { - if (substitutions && substitutions->genericDecl == parentDecl) + auto genSubst = substitutions.As<GenericSubstitution>(); + if (genSubst && genSubst->genericDecl == parentDecl) { // We strip away the specializations that were applied to // the parent, since we were asked for a reference *to* the parent. @@ -1318,12 +1419,12 @@ void Type::accept(IValVisitor* visitor, void* extra) Type* HLSLPatchType::getElementType() { - return this->declRef.substitutions->args[0].As<Type>().Ptr(); + return this->declRef.substitutions.As<GenericSubstitution>()->args[0].As<Type>().Ptr(); } IntVal* HLSLPatchType::getElementCount() { - return this->declRef.substitutions->args[1].As<IntVal>().Ptr(); + return this->declRef.substitutions.As<GenericSubstitution>()->args[1].As<IntVal>().Ptr(); } // Constructors for types @@ -1469,4 +1570,77 @@ void Type::accept(IValVisitor* visitor, void* extra) + void insertSubstAtTop(DeclRefBase & declRef, RefPtr<Substitutions> substToInsert) + { + substToInsert->outer = declRef.substitutions; + declRef.substitutions = substToInsert; + } + + RefPtr<ThisTypeSubstitution> getThisTypeSubst(DeclRefBase & declRef, bool insertSubstEntry) + { + RefPtr<ThisTypeSubstitution> thisSubst; + auto subst = declRef.substitutions; + while (subst) + { + if (auto s = subst.As<ThisTypeSubstitution>()) + { + thisSubst = s; + break; + } + subst = subst->outer; + } + if (!thisSubst) + { + thisSubst = new ThisTypeSubstitution(); + if (insertSubstEntry) + { + insertSubstAtTop(declRef, thisSubst); + } + } + return thisSubst; + } + + RefPtr<ThisTypeSubstitution> getNewThisTypeSubst(DeclRefBase & declRef) + { + auto oldSubst = getThisTypeSubst(declRef, false); + if (oldSubst) + removeSubstitution(declRef, oldSubst); + return getThisTypeSubst(declRef, true); + } + + void removeSubstitution(DeclRefBase & declRef, RefPtr<Substitutions> toRemove) + { + if (!declRef.substitutions) + return; + if (toRemove == declRef.substitutions) + { + declRef.substitutions = declRef.substitutions->outer; + return; + } + auto prev = declRef.substitutions; + auto subst = prev->outer; + while (subst) + { + if (subst == toRemove) + { + prev->outer = subst->outer; + break; + } + prev = subst; + subst = subst->outer; + } + } + + bool hasGenericSubstitutions(RefPtr<Substitutions> subst) + { + auto p = subst.Ptr(); + while (p) + { + if (dynamic_cast<GenericSubstitution*>(p)) + return true; + p = p->outer.Ptr(); + } + return false; + } + } diff --git a/source/slang/syntax.h b/source/slang/syntax.h index 0b5a38631..bda43b336 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 @@ -1155,6 +1156,11 @@ namespace Slang Session* session, Decl* decl); + RefPtr<ThisTypeSubstitution> getNewThisTypeSubst(DeclRefBase & declRef); + RefPtr<ThisTypeSubstitution> getThisTypeSubst(DeclRefBase & declRef, bool insertSubstEntry); + void removeSubstitution(DeclRefBase & declRef, RefPtr<Substitutions> subst); + bool hasGenericSubstitutions(RefPtr<Substitutions> subst); + } // namespace Slang #endif
\ No newline at end of file diff --git a/source/slang/type-defs.h b/source/slang/type-defs.h index 2010d07b4..60f519c82 100644 --- a/source/slang/type-defs.h +++ b/source/slang/type-defs.h @@ -449,7 +449,6 @@ SYNTAX_CLASS(FuncType, Type) FIELD(List<RefPtr<Type>>, paramTypes) FIELD(RefPtr<Type>, resultType) - RAW( FuncType() {} @@ -490,4 +489,4 @@ protected: virtual int GetHashCode() override; virtual Type* CreateCanonicalType() override; ) -END_SYNTAX_CLASS() +END_SYNTAX_CLASS()
\ No newline at end of file diff --git a/tests/compute/assoctype-complex.slang b/tests/compute/assoctype-complex.slang new file mode 100644 index 000000000..fa7fc3b0f --- /dev/null +++ b/tests/compute/assoctype-complex.slang @@ -0,0 +1,50 @@ +//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out + +RWStructuredBuffer<int> outputBuffer; +interface IBase +{ + associatedtype V; + V sub(V a0, V a1); +} +interface ISimple +{ + associatedtype U : IBase; + U.V add(U v0, U v1); +} + +struct Val : IBase +{ + typedef int V; + int base; + V sub(V a0, V a1) + { + return a0 - a1 + base; + } +}; + +struct Simple : ISimple +{ + typedef Val U; + Val.V add(U v0, U v1) + { + return v0.sub(4, v1.sub(1,2)); + } +}; + +__generic<T:ISimple> +T.U.V test(T simple, T.U v0, T.U v1) +{ + return simple.add(v0, v1); +} + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Simple s; + Val v0, v1; + v0.base = 1; + v1.base = 2; + int outVal = test<Simple>(s, v0, v1); // == 4.0 + outputBuffer[dispatchThreadID.x] = outVal; +}
\ No newline at end of file diff --git a/tests/compute/assoctype-complex.slang.expected.txt b/tests/compute/assoctype-complex.slang.expected.txt new file mode 100644 index 000000000..e43ad329a --- /dev/null +++ b/tests/compute/assoctype-complex.slang.expected.txt @@ -0,0 +1,4 @@ +4 +4 +4 +4
\ No newline at end of file diff --git a/tests/compute/assoctype-simple.slang b/tests/compute/assoctype-simple.slang new file mode 100644 index 000000000..0f160c9c0 --- /dev/null +++ b/tests/compute/assoctype-simple.slang @@ -0,0 +1,35 @@ +//TEST(smoke,compute):COMPARE_COMPUTE:-xslang -use-ir +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out +// Confirm that generics syntax can be used in user +// code and generates valid output. + +RWStructuredBuffer<float> outputBuffer; + +interface ISimple +{ + associatedtype U; + U add(U v0, U v1); +} + +struct Simple : ISimple +{ + typedef float U; + U add(U v0, float v1) + { + return v0 + v1; + } +}; + +__generic<T:ISimple> +T.U test(T simple, T.U v0, T.U v1) +{ + return simple.add(v0, v1); +} + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + Simple s; + float outVal = test<Simple>(s, 2.0, 1.0); // == 3.0 + outputBuffer[dispatchThreadID.x] = outVal; +}
\ No newline at end of file diff --git a/tests/compute/assoctype-simple.slang.expected.txt b/tests/compute/assoctype-simple.slang.expected.txt new file mode 100644 index 000000000..e54af3bc8 --- /dev/null +++ b/tests/compute/assoctype-simple.slang.expected.txt @@ -0,0 +1,4 @@ +40400000 +40400000 +40400000 +40400000 diff --git a/tests/compute/explicit-this-expr.slang b/tests/compute/explicit-this-expr.slang index 7bd8dff99..59ce64ed5 100644 --- a/tests/compute/explicit-this-expr.slang +++ b/tests/compute/explicit-this-expr.slang @@ -1,4 +1,4 @@ -//TEST(smoke,compute):COMPARE_COMPUTE:-xslang -use-ir +//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir //TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out // Access fields of a `struct` type from within a "method" by diff --git a/tests/compute/generics-constructor.slang b/tests/compute/generics-constructor.slang new file mode 100644 index 000000000..47dc0272a --- /dev/null +++ b/tests/compute/generics-constructor.slang @@ -0,0 +1,17 @@ +//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out + +RWStructuredBuffer<float> outputBuffer; + +__generic<T:__BuiltinFloatingPointType> +T test(T v0, T v1) +{ + return T(3.0); +} + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + float outVal = test<float>(1.0, 2.0); + outputBuffer[dispatchThreadID.x] = outVal; +}
\ No newline at end of file diff --git a/tests/compute/generics-constructor.slang.expected.txt b/tests/compute/generics-constructor.slang.expected.txt new file mode 100644 index 000000000..e54af3bc8 --- /dev/null +++ b/tests/compute/generics-constructor.slang.expected.txt @@ -0,0 +1,4 @@ +40400000 +40400000 +40400000 +40400000 diff --git a/tests/compute/implicit-this-expr.slang b/tests/compute/implicit-this-expr.slang index 339c5fb6a..32cbd88fc 100644 --- a/tests/compute/implicit-this-expr.slang +++ b/tests/compute/implicit-this-expr.slang @@ -1,4 +1,4 @@ -//TEST(smoke,compute):COMPARE_COMPUTE:-xslang -use-ir +//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir //TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out // Access fields of a `struct` type from within a "method" by diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp index 65d66f812..c5c3f68b8 100644 --- a/tools/render-test/render-d3d11.cpp +++ b/tools/render-test/render-d3d11.cpp @@ -714,7 +714,8 @@ public: if (request.computeShader.name) { auto dxComputeShaderBlob = compileHLSLShader(request.computeShader.source.path, request.computeShader.source.text, request.computeShader.name, request.computeShader.profile); - if (!dxComputeShaderBlob) return nullptr; + if (!dxComputeShaderBlob) + return nullptr; ID3D11ComputeShader* dxComputeShader; diff --git a/tools/slang-test/main.cpp b/tools/slang-test/main.cpp index 7cfa981ae..cb1730c6e 100644 --- a/tools/slang-test/main.cpp +++ b/tools/slang-test/main.cpp @@ -1137,6 +1137,7 @@ TestResult runComputeComparisonImpl(TestInput& input, const char * langOption, S spawner.pushArgument("-o"); auto actualOutputFile = outputStem + ".actual.txt"; spawner.pushArgument(actualOutputFile); + spawner.pushArgument("-xslang -use-ir"); // clear the stale actual output file first. This will allow us to detect error if render-test fails and outputs nothing. File::WriteAllText(actualOutputFile, ""); @@ -1183,8 +1184,8 @@ TestResult runComputeComparisonImpl(TestInput& input, const char * langOption, S } for (int i = 0; i < (int)referenceProgramOutput.Count(); i++) { - auto reference = referenceProgramOutput[i]; - auto actual = actualProgramOutput[i]; + auto reference = String(referenceProgramOutput[i].Trim()); + auto actual = String(actualProgramOutput[i].Trim()); if (actual != reference) { // try to parse reference as float, and compare again |
