@@ -431,10 +431,222 @@ Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue,
431
431
DeclContext *DC, Type paramType,
432
432
bool isAutoClosure) {
433
433
assert (paramType && !paramType->hasError ());
434
- return typeCheckExpression (defaultValue, DC, /* contextualInfo=*/
435
- {paramType, isAutoClosure
436
- ? CTP_AutoclosureDefaultParameter
437
- : CTP_DefaultParameter});
434
+
435
+ auto &ctx = DC->getASTContext ();
436
+
437
+ // First, let's try to type-check default expression using interface
438
+ // type of the parameter, if that succeeds - we are done.
439
+ SolutionApplicationTarget defaultExprTarget (
440
+ defaultValue, DC,
441
+ isAutoClosure ? CTP_AutoclosureDefaultParameter : CTP_DefaultParameter,
442
+ paramType, /* isDiscarded=*/ false );
443
+
444
+ {
445
+ // Buffer all of the diagnostics produced by \c typeCheckExpression
446
+ // since in some cases we need to try type-checking again with a
447
+ // different contextual type, see below.
448
+ DiagnosticTransaction diagnostics (ctx.Diags );
449
+
450
+ // First, let's try to type-check default expression using
451
+ // archetypes, which guarantees that it would work for any
452
+ // substitution of the generic parameter (if they are involved).
453
+ if (auto result = typeCheckExpression (defaultExprTarget)) {
454
+ defaultValue = result->getAsExpr ();
455
+ return defaultValue->getType ();
456
+ }
457
+
458
+ // If inference is disabled, fail.
459
+ if (!ctx.TypeCheckerOpts .EnableTypeInferenceFromDefaultArguments )
460
+ return Type ();
461
+
462
+ // Ignore any diagnostics emitted by the original type-check.
463
+ diagnostics.abort ();
464
+ }
465
+
466
+ // Let's see whether it would be possible to use default expression
467
+ // for generic parameter inference.
468
+ //
469
+ // First, let's check whether:
470
+ // - Parameter type is a generic parameter; and
471
+ // - It's only used in the current position in the parameter list
472
+ // or result. This check makes sure that that generic argument
473
+ // could only come from an explicit argument or this expression.
474
+ //
475
+ // If both of aforementioned conditions are true, let's attempt
476
+ // to open generic parameter and infer the type of this default
477
+ // expression.
478
+ auto interfaceType = paramType->mapTypeOutOfContext ();
479
+ if (!interfaceType->isTypeParameter ())
480
+ return Type ();
481
+
482
+ auto containsType = [&](Type type, Type contained) {
483
+ return type.findIf (
484
+ [&contained](Type nested) { return nested->isEqual (contained); });
485
+ };
486
+
487
+ // Anchor of this default expression.
488
+ auto *anchor = cast<ValueDecl>(DC->getParent ()->getAsDecl ());
489
+
490
+ // Check whether generic parameter is only mentioned once in
491
+ // the anchor's signature.
492
+ {
493
+ auto anchorTy = anchor->getInterfaceType ()->castTo <GenericFunctionType>();
494
+
495
+ // Reject if generic parameter could be inferred from result type.
496
+ if (containsType (anchorTy->getResult (), interfaceType)) {
497
+ ctx.Diags .diagnose (
498
+ defaultValue->getLoc (),
499
+ diag::cannot_default_generic_parameter_inferrable_from_result,
500
+ interfaceType);
501
+ return Type ();
502
+ }
503
+
504
+ // Reject if generic parameter is used in multiple different positions
505
+ // in the parameter list.
506
+
507
+ llvm::SmallVector<unsigned , 2 > affectedParams;
508
+ for (unsigned i : indices (anchorTy->getParams ())) {
509
+ const auto ¶m = anchorTy->getParams ()[i];
510
+
511
+ if (containsType (param.getPlainType (), interfaceType))
512
+ affectedParams.push_back (i);
513
+ }
514
+
515
+ if (affectedParams.size () > 1 ) {
516
+ SmallString<32 > paramBuf;
517
+ llvm::raw_svector_ostream params (paramBuf);
518
+
519
+ interleave (
520
+ affectedParams, [&](const unsigned index) { params << " #" << index; },
521
+ [&] { params << " , " ; });
522
+
523
+ ctx.Diags .diagnose (
524
+ defaultValue->getLoc (),
525
+ diag::
526
+ cannot_default_generic_parameter_inferrable_from_another_parameter,
527
+ interfaceType, params.str ());
528
+ return Type ();
529
+ }
530
+ }
531
+
532
+ auto signature = DC->getGenericSignatureOfContext ();
533
+ assert (signature && " generic parameter without signature?" );
534
+
535
+ ConstraintSystemOptions options;
536
+ options |= ConstraintSystemFlags::AllowFixes;
537
+
538
+ ConstraintSystem cs (DC, options);
539
+
540
+ auto *locator = cs.getConstraintLocator (
541
+ defaultValue, LocatorPathElt::ContextualType (
542
+ defaultExprTarget.getExprContextualTypePurpose ()));
543
+
544
+ // A replacement for generic parameter type to associate any generic
545
+ // requirements with.
546
+ auto *contextualTy = cs.createTypeVariable (locator, /* flags=*/ 0 );
547
+
548
+ auto *requirementBaseLocator = cs.getConstraintLocator (
549
+ locator, LocatorPathElt::OpenedGeneric (signature));
550
+
551
+ // Let's check all of the requirements this parameter is invoved in,
552
+ // If it's connected to any other generic types (directly or through
553
+ // a dependent member type), that means it could be inferred through
554
+ // them e.g. `T: X.Y` or `T == U`.
555
+ {
556
+ auto isViable = [](Type type) {
557
+ return !(type->hasTypeParameter () && type->hasDependentMember ());
558
+ };
559
+
560
+ auto recordRequirement = [&](unsigned index, Requirement requirement,
561
+ ConstraintLocator *locator) {
562
+ cs.openGenericRequirement (DC->getParent (), index, requirement,
563
+ /* skipSelfProtocolConstraint=*/ false , locator,
564
+ [](Type type) -> Type { return type; });
565
+ };
566
+
567
+ auto requirements = signature.getRequirements ();
568
+ for (unsigned reqIdx = 0 ; reqIdx != requirements.size (); ++reqIdx) {
569
+ auto &requirement = requirements[reqIdx];
570
+
571
+ switch (requirement.getKind ()) {
572
+ case RequirementKind::Conformance: {
573
+ if (!requirement.getFirstType ()->isEqual (interfaceType))
574
+ continue ;
575
+
576
+ recordRequirement (reqIdx,
577
+ {RequirementKind::Conformance, contextualTy,
578
+ requirement.getSecondType ()},
579
+ requirementBaseLocator);
580
+ break ;
581
+ }
582
+
583
+ case RequirementKind::Superclass: {
584
+ auto subclassTy = requirement.getFirstType ();
585
+ auto superclassTy = requirement.getSecondType ();
586
+
587
+ if (subclassTy->isEqual (interfaceType) && isViable (superclassTy)) {
588
+ recordRequirement (
589
+ reqIdx, {RequirementKind::Superclass, contextualTy, superclassTy},
590
+ requirementBaseLocator);
591
+ }
592
+
593
+ break ;
594
+ }
595
+
596
+ case RequirementKind::SameType: {
597
+ // If there is a same-type constraint that involves our parameter
598
+ // type, fail the type-check since the type could be inferred
599
+ // through other positions.
600
+ if (containsType (requirement.getFirstType (), interfaceType) ||
601
+ containsType (requirement.getSecondType (), interfaceType)) {
602
+ SmallString<32 > reqBuf;
603
+ llvm::raw_svector_ostream req (reqBuf);
604
+
605
+ requirement.print (req, PrintOptions ());
606
+
607
+ ctx.Diags .diagnose (
608
+ defaultValue->getLoc (),
609
+ diag::
610
+ cannot_default_generic_parameter_inferrable_through_same_type,
611
+ interfaceType, req.str ());
612
+ return Type ();
613
+ }
614
+
615
+ continue ;
616
+ }
617
+
618
+ case RequirementKind::Layout:
619
+ if (!requirement.getFirstType ()->isEqual (interfaceType))
620
+ continue ;
621
+
622
+ recordRequirement (reqIdx,
623
+ {RequirementKind::Layout, contextualTy,
624
+ requirement.getLayoutConstraint ()},
625
+ requirementBaseLocator);
626
+ break ;
627
+ }
628
+ }
629
+ }
630
+
631
+ defaultExprTarget.setExprConversionType (contextualTy);
632
+ cs.setContextualType (defaultValue,
633
+ defaultExprTarget.getExprContextualTypeLoc (),
634
+ defaultExprTarget.getExprContextualTypePurpose ());
635
+
636
+ auto viable = cs.solve (defaultExprTarget, FreeTypeVariableBinding::Disallow);
637
+ if (!viable)
638
+ return Type ();
639
+
640
+ auto &solution = (*viable)[0 ];
641
+
642
+ cs.applySolution (solution);
643
+
644
+ if (auto result = cs.applySolution (solution, defaultExprTarget)) {
645
+ defaultValue = result->getAsExpr ();
646
+ return defaultValue->getType ();
647
+ }
648
+
649
+ return Type ();
438
650
}
439
651
440
652
bool TypeChecker::typeCheckBinding (Pattern *&pattern, Expr *&initializer,
0 commit comments