From ff7c190b838dffc79e5acd555f41506cb52a9f47 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 31 Aug 2017 14:13:28 -0700 Subject: Move implicit conversion operations to stdlib - Previously, there were a variety of rules in `check.cpp` to pick the conversion cost for various cases involving scalar, vector, and matrix types. - The main problem of the previous approach is that any lowering pass would need to convert an arbitrary "type cast" node into the right low-level operation(s). - The new approach is that a type conversion (implicit or explicit) always resolves as a call to a constructor/initializer for the destination type. This means that the existing rules around marking operations as builtins should work for lowering. - The support this, the checking logic needs to perform lookup of intializers/constructors when asked to perform conversion between types. It does this by re-using the existing logic for lookup and overload resolution if/when a type was applied in an ordinary context. - Next, we define a modifier that can be attached to constructors/initializers to mark them as suitable for implicit conversion, and associate them with the correct cost to be used when doing overload comparisons. - We add the modifier to all the scalar-to-scalar cases in the stdlib, using the logic that previously existed in semantic checking. - Next we add cases for general vector-to-scalar conversions that also convert type, using the same cost computation as above. - This probably misses various cases, but at this point they can hopefully be added just in the stdlib. - One gotcha here is that in lowering, we need to make sure to lower any kind of call expression to another call expression of the same AST node class, so that we don't lose information on what casts were implicit/hidden in teh source-to-source case. Two notes for potential longer-term changes: 1. There is still some duplication between the type conversion declarations here and the "join" logic for types used for generic arguments. Ideally we'd eventually clean up the "join" logic to be based on convertability, but that isn't a high priority right now, as long as joins continue to pick the right type. 2. It is a bit gross to have to declare all the N^2 conversions for vector/matrix types to duplicate the cases for scalars. For the simple scalar-to-vector case, we might try to support multiple conversion "steps" where both a scalar-to-scalar and a scalar-to-vector step can be allowed (this could be tagged on the modifiers already introduced). That simple option doesn't scale to vector-to-vector element type conversions, though, where you'd really want to make it a generic with a constraint like: vector init(vector value) where T : ConvertibleFrom; Here the `ConvertibleFrom` interface expresses the fact that a conforming type has an initializer that takes a `U`. What doesn't appear in this context is any notion of conversion costs. We'd need some kind of system for computing the conversion cost of the vector conversion from the cost of the `T` to `U` converion. --- source/slang/check.cpp | 454 +++++++++++++++++++++++++++++++------------------ 1 file changed, 291 insertions(+), 163 deletions(-) (limited to 'source/slang/check.cpp') diff --git a/source/slang/check.cpp b/source/slang/check.cpp index cc2954fc4..ce9b2de55 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -140,14 +140,14 @@ namespace Slang } RefPtr ConstructDeclRefExpr( - DeclRef declRef, + DeclRef declRef, RefPtr baseExpr, - RefPtr originalExpr) + SourceLoc loc) { if (baseExpr) { auto expr = new MemberExpr(); - expr->loc = originalExpr->loc; + expr->loc = loc; expr->BaseExpression = baseExpr; expr->name = declRef.GetName(); expr->type = GetTypeForDeclRef(declRef); @@ -157,7 +157,7 @@ namespace Slang else { auto expr = new VarExpr(); - expr->loc = originalExpr->loc; + expr->loc = loc; expr->name = declRef.GetName(); expr->type = GetTypeForDeclRef(declRef); expr->declRef = declRef; @@ -166,14 +166,14 @@ namespace Slang } RefPtr ConstructDerefExpr( - RefPtr base, - RefPtr originalExpr) + RefPtr base, + SourceLoc loc) { auto ptrLikeType = base->type->As(); SLANG_ASSERT(ptrLikeType); auto derefExpr = new DerefExpr(); - derefExpr->loc = originalExpr->loc; + derefExpr->loc = loc; derefExpr->base = base; derefExpr->type = QualType(ptrLikeType->elementType); @@ -183,9 +183,9 @@ namespace Slang } RefPtr ConstructLookupResultExpr( - LookupResultItem const& item, - RefPtr baseExpr, - RefPtr originalExpr) + LookupResultItem const& item, + RefPtr baseExpr, + SourceLoc loc) { // If we collected any breadcrumbs, then these represent // additional segments of the lookup path that we need @@ -196,28 +196,28 @@ namespace Slang switch (breadcrumb->kind) { case LookupResultItem::Breadcrumb::Kind::Member: - bb = ConstructDeclRefExpr(breadcrumb->declRef, bb, originalExpr); + bb = ConstructDeclRefExpr(breadcrumb->declRef, bb, loc); break; case LookupResultItem::Breadcrumb::Kind::Deref: - bb = ConstructDerefExpr(bb, originalExpr); + bb = ConstructDerefExpr(bb, loc); break; default: SLANG_UNREACHABLE("all cases handle"); } } - return ConstructDeclRefExpr(item.declRef, bb, originalExpr); + return ConstructDeclRefExpr(item.declRef, bb, loc); } RefPtr createLookupResultExpr( - LookupResult const& lookupResult, - RefPtr baseExpr, - RefPtr originalExpr) + LookupResult const& lookupResult, + RefPtr baseExpr, + SourceLoc loc) { if (lookupResult.isOverloaded()) { auto overloadedExpr = new OverloadedExpr(); - overloadedExpr->loc = originalExpr->loc; + overloadedExpr->loc = loc; overloadedExpr->type = QualType( getSession()->getOverloadedType()); overloadedExpr->base = baseExpr; @@ -226,7 +226,7 @@ namespace Slang } else { - return ConstructLookupResultExpr(lookupResult.item, baseExpr, originalExpr); + return ConstructLookupResultExpr(lookupResult.item, baseExpr, loc); } } @@ -264,7 +264,7 @@ namespace Slang } // otherwise, we had a single decl and it was valid, hooray! - return ConstructLookupResultExpr(lookupResult.item, overloadedExpr->base, overloadedExpr); + return ConstructLookupResultExpr(lookupResult.item, overloadedExpr->base, overloadedExpr->loc); } RefPtr ExpectATypeRepr(RefPtr expr) @@ -583,90 +583,6 @@ namespace Slang public: - typedef unsigned int ConversionCost; - enum : ConversionCost - { - // No conversion at all - kConversionCost_None = 0, - - // Conversions based on explicit sub-typing relationships are the cheapest - // - // TODO(tfoley): We will eventually need a discipline for ranking - // when two up-casts are comparable. - kConversionCost_CastToInterface = 50, - - // Conversion that is lossless and keeps the "kind" of the value the same - kConversionCost_RankPromotion = 100, - - // Conversions that are lossless, but change "kind" - kConversionCost_UnsignedToSignedPromotion = 200, - - // Conversion from signed->unsigned integer of same or greater size - kConversionCost_SignedToUnsignedConversion = 300, - - // Cost of converting an integer to a floating-point type - kConversionCost_IntegerToFloatConversion = 400, - - // Catch-all for conversions that should be discouraged - // (i.e., that really shouldn't be made implicitly) - // - // TODO: make these conversions not be allowed implicitly in "Slang mode" - kConversionCost_GeneralConversion = 900, - - // Additional conversion cost to add when promoting from a scalar to - // a vector (this will be added to the cost, if any, of converting - // the element type of the vector) - kConversionCost_ScalarToVector = 1, - }; - - enum BaseTypeConversionKind : uint8_t - { - kBaseTypeConversionKind_Signed, - kBaseTypeConversionKind_Unsigned, - kBaseTypeConversionKind_Float, - kBaseTypeConversionKind_Error, - }; - - enum BaseTypeConversionRank : uint8_t - { - kBaseTypeConversionRank_Bool, - kBaseTypeConversionRank_Int8, - kBaseTypeConversionRank_Int16, - kBaseTypeConversionRank_Int32, - kBaseTypeConversionRank_IntPtr, - kBaseTypeConversionRank_Int64, - kBaseTypeConversionRank_Error, - }; - - struct BaseTypeConversionInfo - { - BaseTypeConversionKind kind; - BaseTypeConversionRank rank; - }; - static BaseTypeConversionInfo GetBaseTypeConversionInfo(BaseType baseType) - { - switch (baseType) - { - #define CASE(TAG, KIND, RANK) \ - case BaseType::TAG: { BaseTypeConversionInfo info = {kBaseTypeConversionKind_##KIND, kBaseTypeConversionRank_##RANK}; return info; } break - - CASE(Bool, Unsigned, Bool); - CASE(Int, Signed, Int32); - CASE(UInt, Unsigned, Int32); - CASE(UInt64, Unsigned, Int64); - CASE(Half, Float, Int16); - CASE(Float, Float, Int32); - CASE(Double, Float, Int64); - CASE(Void, Error, Error); - - #undef CASE - - default: - break; - } - SLANG_UNREACHABLE("all cases handled"); - } - bool ValuesAreEqual( RefPtr left, RefPtr right) @@ -692,6 +608,19 @@ namespace Slang return false; } + // Compute the cost of using a particular declaration to + // perform implicit type conversion. + ConversionCost getImplicitConversionCost( + Decl* decl) + { + if(auto modifier = decl->FindModifier()) + { + return modifier->cost; + } + + return kConversionCost_Explicit; + } + // Central engine for implementing implicit coercion logic bool TryCoerceImpl( RefPtr toType, // the target type for conversion @@ -836,6 +765,7 @@ namespace Slang // +#if 0 if (auto toBasicType = toType->AsBasicType()) { if (auto fromBasicType = fromType->AsBasicType()) @@ -951,6 +881,7 @@ namespace Slang } } } +#endif if (auto toDeclRefType = toType->As()) { @@ -971,7 +902,97 @@ namespace Slang } } - // TODO: more cases! + // 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. + + OverloadResolveContext overloadContext; + + List> args; + args.Add(fromExpr); + + overloadContext.disallowNestedConversions = true; + overloadContext.argCount = 1; + overloadContext.argTypes = &fromType; + + overloadContext.originalExpr = nullptr; + if(fromExpr) + { + overloadContext.loc = fromExpr->loc; + overloadContext.funcLoc = fromExpr->loc; + overloadContext.args = &fromExpr; + } + + overloadContext.baseExpr = nullptr; + overloadContext.mode = OverloadResolveContext::Mode::JustTrying; + + AddTypeOverloadCandidates(toType, overloadContext); + + if(overloadContext.bestCandidates.Count() != 0) + { + // There were multiple candidates that were equally good. + + // First, we will check if these candidates are even applicable. + // If they aren't, then they can't be used for conversion. + if(overloadContext.bestCandidates[0].status != OverloadCandidate::Status::Appicable) + return false; + + // If we reach this point, then we have multiple candidates which are + // all equally applicable, which means we have an ambiguity. + // If the user is just querying whether a conversion is possible, we + // will tell them it is, because ambiguity should trigger an ambiguity + // error, and not a "no conversion possible" error. + + // We will compute a nominal conversion cost as the minimum over + // all the conversions available. + ConversionCost cost = kConversionCost_GeneralConversion; + for(auto candidate : overloadContext.bestCandidates) + { + ConversionCost candidateCost = getImplicitConversionCost( + candidate.item.declRef.getDecl()); + + if(candidateCost < cost) + cost = candidateCost; + } + + if(outCost) + *outCost = cost; + + if(outToExpr) + { + // The user is asking for us to actually perform the conversion, + // so we need to generate an appropriate expression here. + + throw "foo bar baz"; + } + + return true; + } + else if(overloadContext.bestCandidate) + { + // There is a single best candidate for conversion. + + // It might not actually be usable, so let's check that first. + if(overloadContext.bestCandidate->status != OverloadCandidate::Status::Appicable) + return false; + + // Okay, it is applicable, and we just need to let the user + // know about it, and optionally construct a call. + + // We need to extract the conversion cost from the candidate we found. + ConversionCost cost = getImplicitConversionCost( + overloadContext.bestCandidate->item.declRef.getDecl());; + + if(outCost) + *outCost = cost; + + if(outToExpr) + { + *outToExpr = CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate); + } + + return true; + } return false; } @@ -991,7 +1012,7 @@ namespace Slang } RefPtr CreateImplicitCastExpr( - RefPtr toType, + RefPtr toType, RefPtr fromExpr) { // In "rewrite" mode, we will generate a different syntax node @@ -1007,10 +1028,17 @@ namespace Slang castExpr = new ImplicitCastExpr(); } + auto typeType = new TypeType(); + typeType->type = toType; + + auto typeExpr = new SharedTypeExpr(); + typeExpr->type.type = typeType; + typeExpr->base.type = toType; + castExpr->loc = fromExpr->loc; - castExpr->TargetType.type = toType; + castExpr->FunctionExpr = typeExpr; castExpr->type = QualType(toType); - castExpr->Expression = fromExpr; + castExpr->Arguments.Add(fromExpr); return castExpr; } @@ -2272,7 +2300,7 @@ namespace Slang } else if(auto castExpr = dynamic_cast(expr)) { - auto val = TryConstantFoldExpr(castExpr->Expression.Ptr()); + auto val = TryConstantFoldExpr(castExpr->Arguments[0].Ptr()); if(val) return val; } @@ -2457,7 +2485,7 @@ namespace Slang } RefPtr subscriptFuncExpr = createLookupResultExpr( - lookupResult, subscriptExpr->BaseExpression, subscriptExpr); + lookupResult, subscriptExpr->BaseExpression, subscriptExpr->loc); // Now that we know there is at least one subscript member, // we will construct a reference to it and try to call it @@ -2982,7 +3010,32 @@ namespace Slang ForReal, }; - RefPtr appExpr; + // Location to use when reporting overload-resolution errors. + SourceLoc loc; + + // The original expression (if any) that triggered things + RefPtr originalExpr; + + // Source location of the "function" part of the expression, if any + SourceLoc funcLoc; + + // The original arguments to the call + UInt argCount = 0; + RefPtr* args = nullptr; + RefPtr* argTypes = nullptr; + + UInt getArgCount() { return argCount; } + RefPtr& getArg(UInt index) { return args[index]; } + RefPtr& getArgType(UInt index) + { + if(argTypes) + return argTypes[index]; + else + return getArg(index)->type.type; + } + + bool disallowNestedConversions = false; + RefPtr baseExpr; // Are we still trying out candidates, or are we @@ -3060,7 +3113,7 @@ namespace Slang OverloadResolveContext& context, OverloadCandidate const& candidate) { - UInt argCount = context.appExpr->Arguments.Count(); + UInt argCount = context.getArgCount(); ParamCounts paramCounts = { 0, 0 }; switch (candidate.flavor) { @@ -3087,7 +3140,7 @@ namespace Slang { if (!isRewriteMode()) { - getSink()->diagnose(context.appExpr, Diagnostics::notEnoughArguments, argCount, paramCounts.required); + getSink()->diagnose(context.loc, Diagnostics::notEnoughArguments, argCount, paramCounts.required); } } else @@ -3095,7 +3148,7 @@ namespace Slang SLANG_ASSERT(argCount > paramCounts.allowed); if (!isRewriteMode()) { - getSink()->diagnose(context.appExpr, Diagnostics::tooManyArguments, argCount, paramCounts.allowed); + getSink()->diagnose(context.loc, Diagnostics::tooManyArguments, argCount, paramCounts.allowed); } } } @@ -3107,7 +3160,7 @@ namespace Slang OverloadResolveContext& context, OverloadCandidate const& candidate) { - auto expr = context.appExpr; + auto expr = context.originalExpr; auto decl = candidate.item.declRef.decl; @@ -3120,7 +3173,7 @@ namespace Slang { if (!isRewriteMode()) { - getSink()->diagnose(context.appExpr, Diagnostics::expectedPrefixOperator); + getSink()->diagnose(context.loc, Diagnostics::expectedPrefixOperator); getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName()); } } @@ -3136,7 +3189,7 @@ namespace Slang { if (!isRewriteMode()) { - getSink()->diagnose(context.appExpr, Diagnostics::expectedPostfixOperator); + getSink()->diagnose(context.loc, Diagnostics::expectedPostfixOperator); getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName()); } } @@ -3155,8 +3208,6 @@ namespace Slang OverloadResolveContext& context, OverloadCandidate& candidate) { - auto& args = context.appExpr->Arguments; - auto genericDeclRef = candidate.item.declRef.As(); int aa = 0; @@ -3164,7 +3215,7 @@ namespace Slang { if (auto typeParamRef = memberRef.As()) { - auto arg = args[aa++]; + auto arg = context.getArg(aa++); if (context.mode == OverloadResolveContext::Mode::JustTrying) { @@ -3180,7 +3231,7 @@ namespace Slang } else if (auto valParamRef = memberRef.As()) { - auto arg = args[aa++]; + auto arg = context.getArg(aa++); if (context.mode == OverloadResolveContext::Mode::JustTrying) { @@ -3210,8 +3261,7 @@ namespace Slang OverloadResolveContext& context, OverloadCandidate& candidate) { - auto& args = context.appExpr->Arguments; - UInt argCount = args.Count(); + UInt argCount = context.getArgCount(); List> params; switch (candidate.flavor) @@ -3234,13 +3284,20 @@ namespace Slang for (UInt ii = 0; ii < argCount; ++ii) { - auto& arg = args[ii]; + auto& arg = context.getArg(ii); + auto argType = context.getArgType(ii); auto param = params[ii]; if (context.mode == OverloadResolveContext::Mode::JustTrying) { ConversionCost cost = kConversionCost_None; - if (!CanCoerce(GetType(param), arg->type, &cost)) + if( context.disallowNestedConversions ) + { + // We need an exact match in this case. + if(!GetType(param)->Equals(argType)) + return false; + } + else if (!CanCoerce(GetType(param), argType, &cost)) { return false; } @@ -3288,28 +3345,31 @@ namespace Slang // Create the representation of a given generic applied to some arguments RefPtr CreateGenericDeclRef( - RefPtr baseExpr, - RefPtr appExpr) + RefPtr baseExpr, + RefPtr originalExpr, + UInt argCount, + RefPtr const* args) { auto baseDeclRefExpr = baseExpr.As(); if (!baseDeclRefExpr) { SLANG_DIAGNOSE_UNEXPECTED(getSink(), baseExpr, "expected a reference to a generic declaration"); - return CreateErrorExpr(appExpr.Ptr()); + return CreateErrorExpr(originalExpr); } auto baseGenericRef = baseDeclRefExpr->declRef.As(); if (!baseGenericRef) { SLANG_DIAGNOSE_UNEXPECTED(getSink(), baseExpr, "expected a reference to a generic declaration"); - return CreateErrorExpr(appExpr.Ptr()); + return CreateErrorExpr(originalExpr); } RefPtr subst = new Substitutions(); subst->genericDecl = baseGenericRef.getDecl(); subst->outer = baseGenericRef.substitutions; - for (auto arg : appExpr->Arguments) + for(UInt aa = 0; aa < argCount; ++aa) { + auto arg = args[aa]; subst->args.Add(ExtractGenericArgVal(arg)); } @@ -3318,7 +3378,7 @@ namespace Slang return ConstructDeclRefExpr( innerDeclRef, nullptr, - appExpr); + originalExpr->loc); } // Take an overload candidate that previously got through @@ -3334,11 +3394,11 @@ namespace Slang // special case for generic argument inference failure if (candidate.status == OverloadCandidate::Status::GenericArgumentInferenceFailed) { - String callString = GetCallSignatureString(context.appExpr); + String callString = getCallSignatureString(context); if (!isRewriteMode()) { getSink()->diagnose( - context.appExpr, + context.loc, Diagnostics::genericArgumentInferenceFailed, callString); @@ -3349,7 +3409,6 @@ namespace Slang } context.mode = OverloadResolveContext::Mode::ForReal; - context.appExpr->type = QualType(getSession()->getErrorType()); if (!TryCheckOverloadCandidateArity(context, candidate)) goto error; @@ -3365,41 +3424,66 @@ namespace Slang { auto baseExpr = ConstructLookupResultExpr( - candidate.item, context.baseExpr, context.appExpr->FunctionExpr); + candidate.item, context.baseExpr, context.funcLoc); switch(candidate.flavor) { case OverloadCandidate::Flavor::Func: - context.appExpr->FunctionExpr = baseExpr; - context.appExpr->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()) { - for(auto setter : subscriptDeclRef.getDecl()->getMembersOfType()) + RefPtr callExpr = context.originalExpr.As(); + if(!callExpr) { - context.appExpr->type.IsLeftValue = true; + callExpr = new InvokeExpr(); + callExpr->loc = context.loc; + + for(UInt aa = 0; aa < context.argCount; ++aa) + callExpr->Arguments.Add(context.getArg(aa)); + } + + + callExpr->FunctionExpr = baseExpr; + 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()) + { + for(auto setter : subscriptDeclRef.getDecl()->getMembersOfType()) + { + callExpr->type.IsLeftValue = true; + } } - } - // TODO: there may be other cases that confer l-value-ness + // TODO: there may be other cases that confer l-value-ness + + return callExpr; + } - return context.appExpr; break; case OverloadCandidate::Flavor::Generic: - return CreateGenericDeclRef(baseExpr, context.appExpr); + return CreateGenericDeclRef(baseExpr, context.originalExpr, + context.argCount, + context.args); break; default: - SLANG_DIAGNOSE_UNEXPECTED(getSink(), context.appExpr, "unknown overload candidate flavor"); + SLANG_DIAGNOSE_UNEXPECTED(getSink(), context.loc, "unknown overload candidate flavor"); break; } } error: - return CreateErrorExpr(context.appExpr.Ptr()); + + if(context.originalExpr) + { + return CreateErrorExpr(context.originalExpr.Ptr()); + } + else + { + SLANG_DIAGNOSE_UNEXPECTED(getSink(), context.loc, "no original expression for overload result"); + return nullptr; + } } // Implement a comparison operation between overload candidates, @@ -3859,6 +3943,7 @@ namespace Slang } } +#if 0 bool TryUnifyArgAndParamTypes( ConstraintSystem& system, RefPtr argExpr, @@ -3869,6 +3954,7 @@ namespace Slang // an overload group... return TryUnifyTypes(system, argExpr->type, GetType(paramDeclRef)); } +#endif // Take a generic declaration and try to specialize its parameters // so that the resulting inner declaration can be applicable in @@ -3889,10 +3975,9 @@ namespace Slang // to match it up with the arguments accordingly... if (auto funcDeclRef = unspecializedInnerRef.As()) { - auto& args = context.appExpr->Arguments; auto params = GetParameters(funcDeclRef).ToArray(); - UInt argCount = args.Count(); + UInt argCount = context.getArgCount(); UInt paramCount = params.Count(); // Bail out on mismatch. @@ -3926,7 +4011,7 @@ namespace Slang // So the question is then whether a mismatch during the // unification step should be taken as an immediate failure... - TryUnifyArgAndParamTypes(constraints, args[aa], params[aa]); + TryUnifyTypes(constraints, context.getArgType(aa), GetType(params[aa])); #endif } } @@ -4225,21 +4310,28 @@ namespace Slang return getDeclSignatureString(item.declRef); } - String GetCallSignatureString(RefPtr expr) + String getCallSignatureString( + OverloadResolveContext& context) { - StringBuilder argsListBuilder; + StringBuilder argsListBuilder; argsListBuilder << "("; - bool first = true; - for (auto a : expr->Arguments) + + UInt argCount = context.getArgCount(); + for( UInt aa = 0; aa < argCount; ++aa ) { - if (!first) argsListBuilder << ", "; - argsListBuilder << a->type->ToString(); - first = false; + if(aa != 0) argsListBuilder << ", "; + argsListBuilder << context.getArgType(aa)->ToString(); } argsListBuilder << ")"; return argsListBuilder.ProduceString(); } +#if 0 + String GetCallSignatureString(RefPtr expr) + { + return getCallSignatureString(expr->Arguments); + } +#endif RefPtr ResolveInvoke(InvokeExpr * expr) { @@ -4262,7 +4354,14 @@ namespace Slang } OverloadResolveContext context; - context.appExpr = expr; + + context.originalExpr = expr; + context.funcLoc = funcExpr->loc; + + context.argCount = expr->Arguments.Count(); + context.args = expr->Arguments.Buffer(); + context.loc = expr->loc; + if (auto funcMemberExpr = funcExpr.As()) { context.baseExpr = funcMemberExpr->BaseExpression; @@ -4297,7 +4396,7 @@ namespace Slang else if(auto baseMemberRef = funcExpr.As()) funcName = baseMemberRef->name; - String argsList = GetCallSignatureString(expr); + String argsList = getCallSignatureString(context); if (context.bestCandidates[0].status != OverloadCandidate::Status::Appicable) { @@ -4457,7 +4556,12 @@ namespace Slang // Otherwise, let's start looking at how to find an overload... OverloadResolveContext context; - context.appExpr = genericAppExpr; + context.originalExpr = genericAppExpr; + context.funcLoc = baseExpr->loc; + context.argCount = args.Count(); + context.args = args.Buffer(); + context.loc = genericAppExpr->loc; + context.baseExpr = GetBaseExpr(baseExpr); AddGenericOverloadCandidates(baseExpr, context); @@ -4606,7 +4710,7 @@ namespace Slang return createLookupResultExpr( lookupResult, nullptr, - expr); + expr->loc); } if (!isRewriteMode()) @@ -4619,6 +4723,29 @@ namespace Slang RefPtr visitTypeCastExpr(TypeCastExpr * expr) { + // Check the term we are applying first + auto funcExpr = expr->FunctionExpr; + funcExpr = CheckTerm(funcExpr); + + // Now ensure that the term represnets a (proper) type. + TypeExp typeExp; + typeExp.exp = funcExpr; + typeExp = CheckProperType(typeExp); + + expr->FunctionExpr = typeExp.exp; + expr->type.type = typeExp.type; + + // Next check the argument expression (there should be only one) + for (auto & arg : expr->Arguments) + { + arg = CheckExpr(arg); + } + + // Now process this like any other explicit call (so casts + // and constructor calls are semantically equivalent). + return CheckInvokeExprWithCheckedOperands(expr); + +#if 0 expr->Expression = CheckTerm(expr->Expression); auto targetType = CheckProperType(expr->TargetType); expr->TargetType = targetType; @@ -4659,6 +4786,7 @@ namespace Slang } expr->type = QualType(getSession()->getErrorType()); return expr; +#endif } // Get the type to use when referencing a declaration @@ -4906,7 +5034,7 @@ namespace Slang return createLookupResultExpr( lookupResult, expr->BaseExpression, - expr); + expr->loc); } } } @@ -4928,7 +5056,7 @@ namespace Slang return createLookupResultExpr( lookupResult, expr->BaseExpression, - expr); + expr->loc); } // catch-all -- cgit v1.2.3