summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-decl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-check-decl.cpp')
-rw-r--r--source/slang/slang-check-decl.cpp136
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,