Appearance
| 1 | namespace Semantic is | |
| 2 | use Source.LOCATION; | |
| 3 | ||
| 4 | use Types.Type; | |
| 5 | ||
| 6 | // Pre-specialisation pass run on a null first overload-resolution | |
| 7 | // of a constructor call. When the call carries a return-type / | |
| 8 | // assignment-type / let-init constraint, each candidate is asked | |
| 9 | // OWNER_CONSTRAINT_SPECIALIZER.specialize_from_constraint: its | |
| 10 | // direct / variant-of-constraint / ancestor-unification paths pin | |
| 11 | // whatever owner-generic args the constraint covers, turning | |
| 12 | // wild formals into concrete ones so the re-resolve's per-arg | |
| 13 | // binding becomes verification rather than inference. | |
| 14 | // | |
| 15 | // The caller passes the candidate list, retries overload resolution | |
| 16 | // against the returned list only when this method returns non-null, | |
| 17 | // and falls through (preserving the original null result and its | |
| 18 | // diagnostic) when no candidate was specialised. Returning null on | |
| 19 | // "no progress" — rather than the original list — keeps the | |
| 20 | // existing diagnostic intact and avoids a wasted second resolver | |
| 21 | // pass when the constraint contributes nothing. | |
| 22 | // | |
| 23 | // Stateless: callers can share a single instance. | |
| 24 | class CONSTRUCTOR_CONSTRAINT_RETRY is | |
| 25 | _owner_constraint_specializer: OWNER_CONSTRAINT_SPECIALIZER; | |
| 26 | ||
| 27 | init(owner_constraint_specializer: OWNER_CONSTRAINT_SPECIALIZER) is | |
| 28 | super.init(); | |
| 29 | _owner_constraint_specializer = owner_constraint_specializer; | |
| 30 | si | |
| 31 | ||
| 32 | // For each candidate in `candidates`, run specialize_from_ | |
| 33 | // constraint against `constraint`. Returns the resulting list | |
| 34 | // iff at least one candidate was specialised (i.e. the call | |
| 35 | // would change the resolver's input); otherwise null. The | |
| 36 | // returned list contains all candidates in input order, with | |
| 37 | // each replaced by its specialised form where applicable — | |
| 38 | // candidates the constraint doesn't touch come through | |
| 39 | // unchanged so the resolver keeps seeing the full set. | |
| 40 | try_specialise_candidates( | |
| 41 | location: LOCATION, | |
| 42 | candidates: Collections.Iterable[Symbols.Function]?, | |
| 43 | constraint: Type? | |
| 44 | ) -> Collections.List[Symbols.Function]? is | |
| 45 | if !candidates? \/ !constraint? \/ constraint.is_sentinel \/ constraint.is_inferred then | |
| 46 | return null; | |
| 47 | fi | |
| 48 | ||
| 49 | let result = Collections.LIST[Symbols.Function](); | |
| 50 | let any_specialised mut = false; | |
| 51 | ||
| 52 | for f in candidates do | |
| 53 | let specialised = _owner_constraint_specializer.specialize_from_constraint(location, f, constraint); | |
| 54 | ||
| 55 | if specialised != f then | |
| 56 | any_specialised = true; | |
| 57 | fi | |
| 58 | ||
| 59 | result.add(specialised); | |
| 60 | od | |
| 61 | ||
| 62 | if !any_specialised then | |
| 63 | return null; | |
| 64 | fi | |
| 65 | ||
| 66 | return result; | |
| 67 | si | |
| 68 | si | |
| 69 | si |