@@ -345,6 +345,120 @@ static Type substPrefixType(Type type, unsigned suffixLength, Type prefixType,
345
345
std::nullopt);
346
346
}
347
347
348
+ Type RequirementMachine::getReducedTypeParameter (
349
+ CanType t,
350
+ ArrayRef<GenericTypeParamType *> genericParams) const {
351
+ // Get a simplified term T.
352
+ auto term = Context.getMutableTermForType (t, /* proto=*/ nullptr );
353
+ System.simplify (term);
354
+
355
+ // We need to handle "purely concrete" member types, eg if I have a
356
+ // signature <T where T == Foo>, and we're asked to reduce the
357
+ // type T.[P:A] where Foo : A.
358
+ //
359
+ // This comes up because we can derive the signature <T where T == Foo>
360
+ // from a generic signature like <T where T : P>; adding the
361
+ // concrete requirement 'T == Foo' renders 'T : P' redundant. We then
362
+ // want to take interface types written against the original signature
363
+ // and reduce them with respect to the derived signature.
364
+ //
365
+ // The problem is that T.[P:A] is not a valid term in the rewrite system
366
+ // for <T where T == Foo>, since we do not have the requirement T : P.
367
+ //
368
+ // A more principled solution would build a substitution map when
369
+ // building a derived generic signature that adds new requirements;
370
+ // interface types would first be substituted before being reduced
371
+ // in the new signature.
372
+ //
373
+ // For now, we handle this with a two-step process; we split a term up
374
+ // into a longest valid prefix, which must resolve to a concrete type,
375
+ // and the remaining suffix, which we use to perform a concrete
376
+ // substitution using subst().
377
+
378
+ // In the below, let T be a type term, with T == UV, where U is the
379
+ // longest valid prefix.
380
+ //
381
+ // Note that V can be empty if T is fully valid; we expect this to be
382
+ // true most of the time.
383
+ auto prefix = getLongestValidPrefix (term);
384
+
385
+ // Get a type (concrete or dependent) for U.
386
+ auto prefixType = [&]() -> Type {
387
+ if (prefix.empty ())
388
+ return Type ();
389
+
390
+ verify (prefix);
391
+
392
+ auto *props = Map.lookUpProperties (prefix);
393
+ if (props) {
394
+ if (props->isConcreteType ()) {
395
+ auto concreteType = props->getConcreteType (genericParams,
396
+ prefix, Map);
397
+ if (!concreteType->hasTypeParameter ())
398
+ return concreteType;
399
+
400
+ // FIXME: Recursion guard is needed here
401
+ return getReducedType (concreteType, genericParams);
402
+ }
403
+
404
+ // Skip this part if the entire input term is valid, because in that
405
+ // case we don't want to replace the term with its superclass bound;
406
+ // unlike a fixed concrete type, the superclass bound only comes into
407
+ // play when looking up a member type.
408
+ if (props->hasSuperclassBound () &&
409
+ prefix.size () != term.size ()) {
410
+ auto superclass = props->getSuperclassBound (genericParams,
411
+ prefix, Map);
412
+ if (!superclass->hasTypeParameter ())
413
+ return superclass;
414
+
415
+ // FIXME: Recursion guard is needed here
416
+ return getReducedType (superclass, genericParams);
417
+ }
418
+ }
419
+
420
+ return Map.getTypeForTerm (prefix, genericParams);
421
+ }();
422
+
423
+ // If T is already valid, the longest valid prefix U of T is T itself, and
424
+ // V is empty. Just return the type we computed above.
425
+ //
426
+ // This is the only case where U is allowed to be dependent.
427
+ if (prefix.size () == term.size ())
428
+ return prefixType;
429
+
430
+ // If U is not concrete, we have an invalid member type of a dependent
431
+ // type, which is not valid in this generic signature. Give up.
432
+ if (prefix.empty () || prefixType->isTypeParameter ()) {
433
+ llvm::errs () << " \n " ;
434
+ llvm::errs () << " getReducedTypeParameter() was called\n " ;
435
+ llvm::errs () << " with " << Sig << " ,\n " ;
436
+ llvm::errs () << " and " << t << " .\n\n " ;
437
+ if (prefix.empty ()) {
438
+ llvm::errs () << " This type parameter contains the generic parameter "
439
+ << Type (t->getRootGenericParam ()) << " .\n\n " ;
440
+ llvm::errs () << " This generic parameter is not part of the given "
441
+ << " generic signature.\n\n " ;
442
+ } else {
443
+ llvm::errs () << " This type parameter's reduced term is " << term << " .\n\n " ;
444
+ llvm::errs () << " This is not a valid term, because " << prefix << " does not "
445
+ << " have a member type named " << term[prefix.size ()] << " .\n\n " ;
446
+ }
447
+ llvm::errs () << " This usually indicates the caller passed the wrong type or "
448
+ << " generic signature to getReducedType().\n\n " ;
449
+
450
+ dump (llvm::errs ());
451
+ abort ();
452
+ }
453
+
454
+ // Compute the type of the unresolved suffix term V.
455
+ auto substType = substPrefixType (t, term.size () - prefix.size (),
456
+ prefixType, Sig);
457
+
458
+ // FIXME: Recursion guard is needed here
459
+ return getReducedType (substType, genericParams);
460
+ }
461
+
348
462
// / Unlike most other queries, the input type can be any type, not just a
349
463
// / type parameter.
350
464
// /
@@ -375,117 +489,7 @@ Type RequirementMachine::getReducedType(
375
489
if (!t->isTypeParameter ())
376
490
return std::nullopt;
377
491
378
- // Get a simplified term T.
379
- auto term = Context.getMutableTermForType (t->getCanonicalType (),
380
- /* proto=*/ nullptr );
381
- System.simplify (term);
382
-
383
- // We need to handle "purely concrete" member types, eg if I have a
384
- // signature <T where T == Foo>, and we're asked to reduce the
385
- // type T.[P:A] where Foo : A.
386
- //
387
- // This comes up because we can derive the signature <T where T == Foo>
388
- // from a generic signature like <T where T : P>; adding the
389
- // concrete requirement 'T == Foo' renders 'T : P' redundant. We then
390
- // want to take interface types written against the original signature
391
- // and reduce them with respect to the derived signature.
392
- //
393
- // The problem is that T.[P:A] is not a valid term in the rewrite system
394
- // for <T where T == Foo>, since we do not have the requirement T : P.
395
- //
396
- // A more principled solution would build a substitution map when
397
- // building a derived generic signature that adds new requirements;
398
- // interface types would first be substituted before being reduced
399
- // in the new signature.
400
- //
401
- // For now, we handle this with a two-step process; we split a term up
402
- // into a longest valid prefix, which must resolve to a concrete type,
403
- // and the remaining suffix, which we use to perform a concrete
404
- // substitution using subst().
405
-
406
- // In the below, let T be a type term, with T == UV, where U is the
407
- // longest valid prefix.
408
- //
409
- // Note that V can be empty if T is fully valid; we expect this to be
410
- // true most of the time.
411
- auto prefix = getLongestValidPrefix (term);
412
-
413
- // Get a type (concrete or dependent) for U.
414
- auto prefixType = [&]() -> Type {
415
- if (prefix.empty ())
416
- return Type ();
417
-
418
- verify (prefix);
419
-
420
- auto *props = Map.lookUpProperties (prefix);
421
- if (props) {
422
- if (props->isConcreteType ()) {
423
- auto concreteType = props->getConcreteType (genericParams,
424
- prefix, Map);
425
- if (!concreteType->hasTypeParameter ())
426
- return concreteType;
427
-
428
- // FIXME: Recursion guard is needed here
429
- return getReducedType (concreteType, genericParams);
430
- }
431
-
432
- // Skip this part if the entire input term is valid, because in that
433
- // case we don't want to replace the term with its superclass bound;
434
- // unlike a fixed concrete type, the superclass bound only comes into
435
- // play when looking up a member type.
436
- if (props->hasSuperclassBound () &&
437
- prefix.size () != term.size ()) {
438
- auto superclass = props->getSuperclassBound (genericParams,
439
- prefix, Map);
440
- if (!superclass->hasTypeParameter ())
441
- return superclass;
442
-
443
- // FIXME: Recursion guard is needed here
444
- return getReducedType (superclass, genericParams);
445
- }
446
- }
447
-
448
- return Map.getTypeForTerm (prefix, genericParams);
449
- }();
450
-
451
- // If T is already valid, the longest valid prefix U of T is T itself, and
452
- // V is empty. Just return the type we computed above.
453
- //
454
- // This is the only case where U is allowed to be dependent.
455
- if (prefix.size () == term.size ())
456
- return prefixType;
457
-
458
- // If U is not concrete, we have an invalid member type of a dependent
459
- // type, which is not valid in this generic signature. Give up.
460
- if (prefix.empty () || prefixType->isTypeParameter ()) {
461
- llvm::errs () << " \n " ;
462
- llvm::errs () << " getReducedType() was called\n " ;
463
- llvm::errs () << " with " << Sig << " ,\n " ;
464
- llvm::errs () << " and " << type << " .\n\n " ;
465
- llvm::errs () << " This type contains the type parameter " << t << " .\n\n " ;
466
- if (prefix.empty ()) {
467
- llvm::errs () << " This type parameter contains the generic parameter "
468
- << Type (t->getRootGenericParam ()) << " .\n\n " ;
469
- llvm::errs () << " This generic parameter is not part of the given "
470
- << " generic signature.\n\n " ;
471
- } else {
472
- llvm::errs () << " This type parameter's reduced term is " << term << " .\n\n " ;
473
- llvm::errs () << " This is not a valid term, because " << prefix << " does not "
474
- << " have a member type named " << term[prefix.size ()] << " .\n\n " ;
475
- }
476
- llvm::errs () << " This usually indicates the caller passed the wrong type or "
477
- << " generic signature to getReducedType().\n\n " ;
478
-
479
- dump (llvm::errs ());
480
- abort ();
481
- }
482
-
483
- // Compute the type of the unresolved suffix term V.
484
- auto substType = substPrefixType (t, term.size () - prefix.size (),
485
- prefixType, Sig);
486
-
487
- // FIXME: Recursion guard is needed here
488
- return getReducedType (substType, genericParams);
492
+ return getReducedTypeParameter (t->getCanonicalType (), genericParams);
489
493
});
490
494
}
491
495
0 commit comments