diff options
Diffstat (limited to 'source/slang/slang-check-decl.cpp')
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 136 |
1 files changed, 93 insertions, 43 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index cebe1bb00..4ebad6392 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -5330,7 +5330,8 @@ bool SemanticsVisitor::trySynthesizeMethodRequirementWitness( ConformanceCheckingContext* context, LookupResult const& lookupResult, DeclRef<FuncDecl> requiredMemberDeclRef, - RefPtr<WitnessTable> witnessTable) + RefPtr<WitnessTable> witnessTable, + MethodWitnessSynthesisFailureDetails* outFailureDetails) { // The situation here is that the context of an inheritance // declaration didn't provide an exact match for a required @@ -5512,10 +5513,8 @@ bool SemanticsVisitor::trySynthesizeMethodRequirementWitness( // if (tempSink.getErrorCount() != 0) { - context->innerSink.diagnose( - SourceLoc(), - Diagnostics::genericSignatureDoesNotMatchRequirement, - baseOverloadedExpr->name); + if (outFailureDetails) + outFailureDetails->reason = WitnessSynthesisFailureReason::GenericSignatureMismatch; return false; } } @@ -5539,31 +5538,42 @@ bool SemanticsVisitor::trySynthesizeMethodRequirementWitness( // so we also need to coerce the result of the call to // the expected type. // - auto coercedCall = subVisitor.coerce(CoercionSite::Return, resultType, checkedCall, getSink()); + auto coercedCall = subVisitor.coerce(CoercionSite::Return, resultType, checkedCall, &tempSink); // If our overload resolution or type coercion failed, // then we have not been able to synthesize a witness // for the requirement. // - // TODO: We might want to detect *why* overload resolution - // or type coercion failed, and report errors accordingly. - // - // More detailed diagnostics could help users understand - // what they did wrong, e.g.: - // - // * "We tried to use `foo(int)` but the interface requires `foo(String)` - // - // * "You have two methods that can apply as `bar()` and we couldn't tell which one you meant - // - // For now we just bail out here and rely on the caller to - // diagnose a generic "failed to satisfying requirement" error. + // Check if this was specifically a return type coercion failure + // and provide a more specific diagnostic. // if (tempSink.getErrorCount() != 0) { - context->innerSink.diagnose( - SourceLoc(), - Diagnostics::cannotResolveOverloadForMethodRequirement, - baseOverloadedExpr->name); + if (outFailureDetails) + outFailureDetails->reason = WitnessSynthesisFailureReason::General; + + // Check if the failure was due to return type coercion + if (!IsErrorExpr(checkedCall) && outFailureDetails) + { + // The call resolved - check if it's a return type mismatch + auto actualReturnType = checkedCall->type; + if (!actualReturnType->equals(resultType)) + { + // Find the actual implementation method that was called + if (auto invokeExpr = as<InvokeExpr>(checkedCall)) + { + if (auto declRefExpr = as<DeclRefExpr>(invokeExpr->functionExpr)) + { + // Store failure details instead of emitting diagnostic immediately + outFailureDetails->reason = + WitnessSynthesisFailureReason::MethodResultTypeMismatch; + outFailureDetails->candidateMethod = declRefExpr->declRef; + outFailureDetails->actualType = actualReturnType; + outFailureDetails->expectedType = resultType; + } + } + } + } return false; } @@ -5607,12 +5617,15 @@ bool SemanticsVisitor::trySynthesizeMethodRequirementWitness( getParameterDirection(calleeParam), getParameterDirection(synParam))) { - context->innerSink.diagnose( - calleeParam, - Diagnostics::parameterDirectionDoesNotMatchRequirement, - calleeParam, - getParameterDirection(calleeParam), - getParameterDirection(synParam)); + if (outFailureDetails) + { + outFailureDetails->reason = + WitnessSynthesisFailureReason::ParameterDirMismatch; + outFailureDetails->candidateMethod = declRefExpr->declRef; + outFailureDetails->actualDir = getParameterDirection(calleeParam); + outFailureDetails->expectedDir = getParameterDirection(synParam); + outFailureDetails->paramDecl = calleeParam; + } return false; } } @@ -6683,7 +6696,8 @@ bool SemanticsVisitor::trySynthesizeRequirementWitness( ConformanceCheckingContext* context, LookupResult const& lookupResult, DeclRef<Decl> requiredMemberDeclRef, - RefPtr<WitnessTable> witnessTable) + RefPtr<WitnessTable> witnessTable, + MethodWitnessSynthesisFailureDetails* outFailureDetails) { SLANG_UNUSED(lookupResult); SLANG_UNUSED(requiredMemberDeclRef); @@ -6696,7 +6710,8 @@ bool SemanticsVisitor::trySynthesizeRequirementWitness( context, lookupResult, requiredFuncDeclRef, - witnessTable)) + witnessTable, + outFailureDetails)) return true; if (auto builtinAttr = @@ -7514,8 +7529,13 @@ bool SemanticsVisitor::findWitnessForInterfaceRequirement( // a wrapper type (struct Foo:IFoo=FooImpl), and we will synthesize // wrappers that redirects the call into the inner element. // - context->innerSink.reset(); - if (trySynthesizeRequirementWitness(context, lookupResult, requiredMemberDeclRef, witnessTable)) + MethodWitnessSynthesisFailureDetails failureDetails = {}; + if (trySynthesizeRequirementWitness( + context, + lookupResult, + requiredMemberDeclRef, + witnessTable, + &failureDetails)) { return true; } @@ -7536,24 +7556,54 @@ bool SemanticsVisitor::findWitnessForInterfaceRequirement( // and if nothing is found we print the candidates that made it // furthest in checking. // - if (!lookupResult.isOverloaded() && lookupResult.isValid()) + // Based on the failure reason, emit specific diagnostics + if (failureDetails.reason == WitnessSynthesisFailureReason::MethodResultTypeMismatch) { + // Emit specific return type mismatch diagnostic getSink()->diagnose( - lookupResult.item.declRef, - Diagnostics::memberDoesNotMatchRequirementSignature, - lookupResult.item.declRef); + failureDetails.candidateMethod, + Diagnostics::memberReturnTypeMismatch, + failureDetails.candidateMethod, + failureDetails.actualType, + failureDetails.expectedType); } - else + else if (failureDetails.reason == WitnessSynthesisFailureReason::ParameterDirMismatch) { getSink()->diagnose( - inheritanceDecl, - Diagnostics::typeDoesntImplementInterfaceRequirement, - subType, - requiredMemberDeclRef); + failureDetails.paramDecl, + Diagnostics::parameterDirectionDoesNotMatchRequirement, + failureDetails.paramDecl, + failureDetails.actualDir, + failureDetails.expectedDir); } - if (context->innerSink.outputBuffer.getLength()) + else if (failureDetails.reason == WitnessSynthesisFailureReason::GenericSignatureMismatch) + { + getSink()->diagnose( + SourceLoc(), + Diagnostics::genericSignatureDoesNotMatchRequirement, + requiredMemberDeclRef.getDecl()->getName()); + } + else { - getSink()->diagnoseRaw(Severity::Note, context->innerSink.outputBuffer.getUnownedSlice()); + // General failure - use existing logic + if (!lookupResult.isOverloaded() && lookupResult.isValid()) + { + getSink()->diagnose( + lookupResult.item.declRef, + Diagnostics::memberDoesNotMatchRequirementSignature, + lookupResult.item.declRef); + } + else + { + getSink()->diagnose( + inheritanceDecl, + Diagnostics::typeDoesntImplementInterfaceRequirement, + subType, + requiredMemberDeclRef); + + for (auto& item : lookupResult) + getSink()->diagnose(item.declRef, Diagnostics::seeOverloadConsidered, item.declRef); + } } getSink()->diagnose( requiredMemberDeclRef, |
