@@ -345,6 +345,120 @@ static Type substPrefixType(Type type, unsigned suffixLength, Type prefixType,
345345 std::nullopt );
346346}
347347
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+
348462// / Unlike most other queries, the input type can be any type, not just a
349463// / type parameter.
350464// /
@@ -375,117 +489,7 @@ Type RequirementMachine::getReducedType(
375489 if (!t->isTypeParameter ())
376490 return std::nullopt ;
377491
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);
489493 });
490494}
491495
0 commit comments