@@ -3412,7 +3412,9 @@ bool SemanticsVisitor::doesSignatureMatchRequirement(
3412
3412
{
3413
3413
auto requiredParam = requiredParams[paramIndex];
3414
3414
auto satisfyingParam = satisfyingParams[paramIndex];
3415
-
3415
+ if (getParameterDirection(requiredParam.getDecl()) !=
3416
+ getParameterDirection(satisfyingParam.getDecl()))
3417
+ return false;
3416
3418
auto requiredParamType = getType(m_astBuilder, requiredParam);
3417
3419
auto satisfyingParamType = getType(m_astBuilder, satisfyingParam);
3418
3420
@@ -4394,14 +4396,14 @@ void SemanticsVisitor::addRequiredParamsToSynthesizedDecl(
4394
4396
//
4395
4397
for (auto paramDeclRef : getParameters(m_astBuilder, requirement))
4396
4398
{
4397
- auto paramType = getType(m_astBuilder, paramDeclRef);
4399
+ auto paramType = QualType( getType(m_astBuilder, paramDeclRef) );
4398
4400
4399
4401
// For each parameter of the requirement, we create a matching
4400
4402
// parameter (same name and type) for the synthesized method.
4401
4403
//
4402
4404
auto synParamDecl = m_astBuilder->create<ParamDecl>();
4403
4405
synParamDecl->nameAndLoc = paramDeclRef.getDecl()->nameAndLoc;
4404
- synParamDecl->type.type = paramType;
4406
+ synParamDecl->type.type = paramType.type ;
4405
4407
4406
4408
// We need to add the parameter as a child declaration of
4407
4409
// the method we are building.
@@ -4410,6 +4412,7 @@ void SemanticsVisitor::addRequiredParamsToSynthesizedDecl(
4410
4412
synthesized->members.add(synParamDecl);
4411
4413
4412
4414
// Add modifiers
4415
+ paramType.isLeftValue = true;
4413
4416
for (auto modifier : paramDeclRef.getDecl()->modifiers)
4414
4417
{
4415
4418
if (as<NoDiffModifier>(modifier))
@@ -4426,6 +4429,8 @@ void SemanticsVisitor::addRequiredParamsToSynthesizedDecl(
4426
4429
(Modifier*)m_astBuilder->createByNodeType(modifier->astNodeType);
4427
4430
clonedModifier->keywordName = modifier->keywordName;
4428
4431
addModifier(synParamDecl, clonedModifier);
4432
+ if (as<ConstRefModifier>(modifier))
4433
+ paramType.isLeftValue = false;
4429
4434
}
4430
4435
}
4431
4436
@@ -4445,6 +4450,7 @@ void SemanticsVisitor::addRequiredParamsToSynthesizedDecl(
4445
4450
synMemberExpr->base = synArg;
4446
4451
synMemberExpr->elementIndices.add((uint32_t)i);
4447
4452
synMemberExpr->type = elementType;
4453
+ synMemberExpr->type.isLeftValue = paramType.isLeftValue;
4448
4454
synArgs.add(synMemberExpr);
4449
4455
}
4450
4456
}
@@ -4572,6 +4578,22 @@ static bool isWrapperTypeDecl(Decl* decl)
4572
4578
return false;
4573
4579
}
4574
4580
4581
+ // Is it allowed to have an interface method parameter whose direction is `reqDir`, and an
4582
+ // implementing method parameter whose direction is `implDir`?
4583
+ //
4584
+ static bool matchParamDirection(ParameterDirection implDir, ParameterDirection reqDir)
4585
+ {
4586
+ // If the parameter directions match exactly, then we are good.
4587
+ if (implDir == reqDir)
4588
+ return true;
4589
+ // Otherwise, we only allow the cases where reqDir is `InOut` and implDir is `In` or `Out`.
4590
+ if (implDir == kParameterDirection_In && reqDir == kParameterDirection_InOut)
4591
+ return true;
4592
+ if (implDir == kParameterDirection_Out && reqDir == kParameterDirection_InOut)
4593
+ return true;
4594
+ return false;
4595
+ }
4596
+
4575
4597
bool SemanticsVisitor::trySynthesizeMethodRequirementWitness(
4576
4598
ConformanceCheckingContext* context,
4577
4599
LookupResult const& lookupResult,
@@ -4749,7 +4771,13 @@ bool SemanticsVisitor::trySynthesizeMethodRequirementWitness(
4749
4771
// If checking the generic app failed, we can't synthesize the witness.
4750
4772
//
4751
4773
if (tempSink.getErrorCount() != 0)
4774
+ {
4775
+ context->innerSink.diagnose(
4776
+ SourceLoc(),
4777
+ Diagnostics::genericSignatureDoesNotMatchRequirement,
4778
+ baseOverloadedExpr->name);
4752
4779
return false;
4780
+ }
4753
4781
}
4754
4782
4755
4783
// We now have the reference to the overload group we plan to call,
@@ -4791,11 +4819,67 @@ bool SemanticsVisitor::trySynthesizeMethodRequirementWitness(
4791
4819
// diagnose a generic "failed to satisfying requirement" error.
4792
4820
//
4793
4821
if (tempSink.getErrorCount() != 0)
4822
+ {
4823
+ context->innerSink.diagnose(
4824
+ SourceLoc(),
4825
+ Diagnostics::cannotResolveOverloadForMethodRequirement,
4826
+ baseOverloadedExpr->name);
4794
4827
return false;
4828
+ }
4795
4829
4796
- // If we were able to type-check the call, then we should
4797
- // be able to finish construction of a suitable witness.
4830
+ // If we were able to type-check the call, we also need to make
4831
+ // sure that the resolved callee member has consistent parameter
4832
+ // direction as the requirement method.
4833
+ //
4834
+ // For example, if there is a requirement:
4835
+ // ```
4836
+ // interface IFoo { void method(out int x); }
4837
+ // ```
4838
+ // and a type:
4839
+ // ```
4840
+ // struct X : IFoo { void method(int x) { ... } }
4841
+ // ```
4842
+ // After we synthesize:
4843
+ // ```
4844
+ // void X::synthesized_method(out int x) { this.method(x); }
4845
+ // ```
4846
+ // The synthesized method will pass all type check just fine,
4847
+ // but we don't want to allow this method to be used as a witness
4848
+ // for the requirement due to inconsistent parameter direction.
4849
+ // So let's check for this now.
4798
4850
//
4851
+ if (auto checkedInvoke = as<InvokeExpr>(checkedCall))
4852
+ {
4853
+ if (auto declRefExpr = as<DeclRefExpr>(checkedInvoke->functionExpr))
4854
+ {
4855
+ if (auto callee = as<CallableDecl>(declRefExpr->declRef))
4856
+ {
4857
+ auto synParams = synFuncDecl->getParameters();
4858
+ auto calleeParams = callee.getDecl()->getParameters();
4859
+ auto synParamIter = synParams.begin();
4860
+ auto calleeParamIter = calleeParams.begin();
4861
+ for (; synParamIter != synParams.end() && calleeParamIter != calleeParams.end();
4862
+ ++synParamIter, ++calleeParamIter)
4863
+ {
4864
+ auto synParam = *synParamIter;
4865
+ auto calleeParam = *calleeParamIter;
4866
+ if (!matchParamDirection(
4867
+ getParameterDirection(calleeParam),
4868
+ getParameterDirection(synParam)))
4869
+ {
4870
+ context->innerSink.diagnose(
4871
+ calleeParam,
4872
+ Diagnostics::parameterDirectionDoesNotMatchRequirement,
4873
+ calleeParam,
4874
+ getParameterDirection(calleeParam),
4875
+ getParameterDirection(synParam));
4876
+ return false;
4877
+ }
4878
+ }
4879
+ }
4880
+ }
4881
+ }
4882
+
4799
4883
// We've already created the outer declaration (including its
4800
4884
// parameters), and the inner expression, so the main work
4801
4885
// that is left is defining the body of the new function,
@@ -5293,7 +5377,7 @@ bool SemanticsVisitor::trySynthesizeWrapperTypePropertyRequirementWitness(
5293
5377
base->name = getName("inner");
5294
5378
propertyRef->baseExpression = base;
5295
5379
innerProperty = innerAccessorDeclRef.getParent();
5296
- propertyRef->name = getParentDecl(innerAccessorDeclRef.getDecl())-> getName();
5380
+ propertyRef->name = requiredMemberDeclRef. getName();
5297
5381
auto checkedPropertyRefExpr = CheckExpr(propertyRef);
5298
5382
5299
5383
if (as<GetterDecl>(requiredAccessorDeclRef))
@@ -6608,6 +6692,7 @@ bool SemanticsVisitor::findWitnessForInterfaceRequirement(
6608
6692
// a wrapper type (struct Foo:IFoo=FooImpl), and we will synthesize
6609
6693
// wrappers that redirects the call into the inner element.
6610
6694
//
6695
+ context->innerSink.reset();
6611
6696
if (trySynthesizeRequirementWitness(context, lookupResult, requiredMemberDeclRef, witnessTable))
6612
6697
{
6613
6698
return true;
@@ -6638,6 +6723,10 @@ bool SemanticsVisitor::findWitnessForInterfaceRequirement(
6638
6723
subType,
6639
6724
requiredMemberDeclRef);
6640
6725
}
6726
+ if (context->innerSink.outputBuffer.getLength())
6727
+ {
6728
+ getSink()->diagnoseRaw(Severity::Note, context->innerSink.outputBuffer.getUnownedSlice());
6729
+ }
6641
6730
getSink()->diagnose(
6642
6731
requiredMemberDeclRef,
6643
6732
Diagnostics::seeDeclarationOfInterfaceRequirement,
0 commit comments