@@ -335,6 +335,9 @@ remapConcreteSubstitutionSchema(CanType concreteType,
335
335
}
336
336
337
337
namespace {
338
+ // / Utility class used by unifyConcreteTypes() and unifySuperclasses()
339
+ // / to walk two concrete types in parallel. Any time there is a mismatch,
340
+ // / records a new induced rule.
338
341
class ConcreteTypeMatcher : public TypeMatcher <ConcreteTypeMatcher> {
339
342
ArrayRef<Term> lhsSubstitutions;
340
343
ArrayRef<Term> rhsSubstitutions;
@@ -357,14 +360,16 @@ namespace {
357
360
358
361
bool mismatch (TypeBase *firstType, TypeBase *secondType,
359
362
Type sugaredFirstType) {
360
- if (isa<GenericTypeParamType>(firstType) &&
361
- isa<GenericTypeParamType>(secondType)) {
363
+ bool firstAbstract = firstType->isTypeParameter ();
364
+ bool secondAbstract = secondType->isTypeParameter ();
365
+
366
+ if (firstAbstract && secondAbstract) {
362
367
// Both sides are type parameters; add a same-type requirement.
363
- unsigned lhsIndex = getGenericParamIndex ( firstType);
364
- unsigned rhsIndex = getGenericParamIndex (secondType );
365
- if (lhsSubstitutions[lhsIndex] != rhsSubstitutions[rhsIndex]) {
366
- MutableTerm lhsTerm (lhsSubstitutions[lhsIndex] );
367
- MutableTerm rhsTerm (rhsSubstitutions[rhsIndex]);
368
+ auto lhsTerm = getRelativeTermForType ( CanType ( firstType),
369
+ lhsSubstitutions, ctx );
370
+ auto rhsTerm = getRelativeTermForType ( CanType (secondType),
371
+ rhsSubstitutions, ctx );
372
+ if (lhsTerm != rhsTerm) {
368
373
if (debug) {
369
374
llvm::dbgs () << " %% Induced rule " << lhsTerm
370
375
<< " == " << rhsTerm << " \n " ;
@@ -374,12 +379,11 @@ namespace {
374
379
return true ;
375
380
}
376
381
377
- if (isa<GenericTypeParamType>(firstType) &&
378
- !isa<GenericTypeParamType>(secondType)) {
382
+ if (firstAbstract && !secondAbstract) {
379
383
// A type parameter is equated with a concrete type; add a concrete
380
384
// type requirement.
381
- unsigned lhsIndex = getGenericParamIndex ( firstType);
382
- MutableTerm subjectTerm ( lhsSubstitutions[lhsIndex] );
385
+ auto subjectTerm = getRelativeTermForType ( CanType ( firstType),
386
+ lhsSubstitutions, ctx );
383
387
384
388
SmallVector<Term, 3 > result;
385
389
auto concreteType = remapConcreteSubstitutionSchema (CanType (secondType),
@@ -397,12 +401,11 @@ namespace {
397
401
return true ;
398
402
}
399
403
400
- if (!isa<GenericTypeParamType>(firstType) &&
401
- isa<GenericTypeParamType>(secondType)) {
404
+ if (!firstAbstract && secondAbstract) {
402
405
// A concrete type is equated with a type parameter; add a concrete
403
406
// type requirement.
404
- unsigned rhsIndex = getGenericParamIndex ( secondType);
405
- MutableTerm subjectTerm ( rhsSubstitutions[rhsIndex] );
407
+ auto subjectTerm = getRelativeTermForType ( CanType ( secondType),
408
+ rhsSubstitutions, ctx );
406
409
407
410
SmallVector<Term, 3 > result;
408
411
auto concreteType = remapConcreteSubstitutionSchema (CanType (firstType),
@@ -420,7 +423,7 @@ namespace {
420
423
return true ;
421
424
}
422
425
423
- // Any other kind of type mismatch involves different concrete types on
426
+ // Any other kind of type mismatch involves conflicting concrete types on
424
427
// both sides, which can only happen on invalid input.
425
428
return false ;
426
429
}
@@ -477,6 +480,87 @@ static bool unifyConcreteTypes(
477
480
return false ;
478
481
}
479
482
483
+ // / When a type parameter has two superclasses, we have to both unify the
484
+ // / type constructor arguments, and record the most derived superclass.
485
+ // /
486
+ // /
487
+ // / For example, if we have this setup:
488
+ // /
489
+ // / class Base<T, T> {}
490
+ // / class Middle<U> : Base<T, T> {}
491
+ // / class Derived : Middle<Int> {}
492
+ // /
493
+ // / T : Base<U, V>
494
+ // / T : Derived
495
+ // /
496
+ // / The most derived superclass requirement is 'T : Derived'.
497
+ // /
498
+ // / The corresponding superclass of 'Derived' is 'Base<Int, Int>', so we
499
+ // / unify the type constructor arguments of 'Base<U, V>' and 'Base<Int, Int>',
500
+ // / which generates two induced rules:
501
+ // /
502
+ // / U.[concrete: Int] => U
503
+ // / V.[concrete: Int] => V
504
+ // /
505
+ // / Returns the most derived superclass, which becomes the new superclass
506
+ // / that gets recorded in the property map.
507
+ static Symbol unifySuperclasses (
508
+ Symbol lhs, Symbol rhs, RewriteContext &ctx,
509
+ SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules,
510
+ bool debug) {
511
+ if (debug) {
512
+ llvm::dbgs () << " % Unifying " << lhs << " with " << rhs << " \n " ;
513
+ }
514
+
515
+ auto lhsType = lhs.getSuperclass ();
516
+ auto rhsType = rhs.getSuperclass ();
517
+
518
+ auto *lhsClass = lhsType.getClassOrBoundGenericClass ();
519
+ assert (lhsClass != nullptr );
520
+
521
+ auto *rhsClass = rhsType.getClassOrBoundGenericClass ();
522
+ assert (rhsClass != nullptr );
523
+
524
+ // First, establish the invariant that lhsClass is either equal to, or
525
+ // is a superclass of rhsClass.
526
+ if (lhsClass == rhsClass ||
527
+ lhsClass->isSuperclassOf (rhsClass)) {
528
+ // Keep going.
529
+ } else if (rhsClass->isSuperclassOf (lhsClass)) {
530
+ std::swap (rhs, lhs);
531
+ std::swap (rhsType, lhsType);
532
+ std::swap (rhsClass, lhsClass);
533
+ } else {
534
+ // FIXME: Diagnose the conflict.
535
+ if (debug) {
536
+ llvm::dbgs () << " %% Unrelated superclass types\n " ;
537
+ }
538
+
539
+ return lhs;
540
+ }
541
+
542
+ if (lhsClass != rhsClass) {
543
+ // Get the corresponding substitutions for the right hand side.
544
+ assert (lhsClass->isSuperclassOf (rhsClass));
545
+ rhsType = rhsType->getSuperclassForDecl (lhsClass)
546
+ ->getCanonicalType ();
547
+ }
548
+
549
+ // Unify type contructor arguments.
550
+ ConcreteTypeMatcher matcher (lhs.getSubstitutions (),
551
+ rhs.getSubstitutions (),
552
+ ctx, inducedRules, debug);
553
+ if (!matcher.match (lhsType, rhsType)) {
554
+ if (debug) {
555
+ llvm::dbgs () << " %% Superclass conflict\n " ;
556
+ }
557
+ return rhs;
558
+ }
559
+
560
+ // Record the more specific class.
561
+ return rhs;
562
+ }
563
+
480
564
void PropertyBag::addProperty (
481
565
Symbol property, RewriteContext &ctx,
482
566
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules,
@@ -496,9 +580,15 @@ void PropertyBag::addProperty(
496
580
return ;
497
581
498
582
case Symbol::Kind::Superclass: {
499
- // FIXME: This needs to find the most derived subclass and also call
500
- // unifyConcreteTypes()
501
- Superclass = property;
583
+ // FIXME: Also handle superclass vs concrete
584
+
585
+ if (Superclass) {
586
+ Superclass = unifySuperclasses (*Superclass, property,
587
+ ctx, inducedRules, debug);
588
+ } else {
589
+ Superclass = property;
590
+ }
591
+
502
592
return ;
503
593
}
504
594
0 commit comments