Skip to content

Commit 76a3139

Browse files
committed
Add section on type-relative name-resolution
1 parent 3eb2b8c commit 76a3139

1 file changed

Lines changed: 199 additions & 2 deletions

File tree

src/names/name-resolution.md

Lines changed: 199 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,8 +558,205 @@ r[names.resolution.primary]
558558
559559
r[names.resolution.type-relative]
560560
## Type-relative resolution
561-
> [!NOTE]
562-
> This is a placeholder for future expansion about type-dependent resolution.
561+
562+
r[names.resolution.type-relative.intro]
563+
_Type-relative resolution_ is the process of tying paths that depend on type
564+
information to the declarations of those entities once that type information is
565+
available in the compiler. This stage of name resolution exclusively applies to
566+
a subset of [Qualified Paths].
567+
568+
Specifically, Qualified Paths from:
569+
570+
- Types
571+
- Expressions
572+
- Patterns
573+
- Structs & Tuple Structs
574+
- these include enums variant structs
575+
576+
Type relative paths fall into the following two categories
577+
578+
- Associated Items
579+
- Variants
580+
581+
`Trait::assoc_item`, `<Type as Trait>::assoc_item` and `Enum::Variant` are
582+
resolved during late resolution. This works because the resolver tracks an
583+
associated `Module` for enums and traits where it can directly lookup these
584+
candidates purely based on information within the enum/trait's original
585+
definition.
586+
587+
`Type::assoc_item`, `<Type>::assoc_item`, `<Enum>::Variant` and
588+
`EnumTyAlias::Variant` are resolved during type checking. These cannot be
589+
resolved earlier because the type checker needs to resolve the trait an
590+
associated item comes from or the definition an alias points to.
591+
592+
r[names.resolution.type-relative.stages]
593+
These type relative paths are resolved separately in item definitions and in function bodies.
594+
595+
r[names.resolution.type-relative.stages.items]
596+
Items:
597+
598+
Type::AssocTy
599+
600+
```rust
601+
// ty path
602+
fn foo<T: Trait>() -> T::AssocTy { .. } // AssocTy can come from a trait and it could be ambiguous with an enum variant
603+
// or an inherent associated type (on unstable)
604+
```
605+
606+
r[names.resolution.type-relative.stages.bodies]
607+
fn bodies:
608+
609+
r[names.resolution.type-relative.stages.bodies.path-expressions]
610+
Path expressions
611+
612+
r[names.resolution.type-relative.stages.bodies.path-expressions.enum-variant-via-alias]
613+
enum variant via alias
614+
615+
```rust
616+
enum Enum {
617+
Variant,
618+
}
619+
type Alias = Enum;
620+
fn main() {
621+
match Enum::Variant {
622+
Alias::Variant => {}
623+
}
624+
}
625+
```
626+
627+
Fully qualified paths for enums are also resolved as type relative names. This
628+
is mainly because the implementation is simpler this way not because this
629+
information would not otherwise be available during primary resolution.
630+
631+
```rust
632+
<Enum>::Variant
633+
```
634+
635+
r[names.resolution.type-relative.stages.bodies.path-expressions.associated-const]
636+
associated consts
637+
638+
```rust
639+
struct Foo;
640+
641+
impl Foo {
642+
const C: u8 = 8;
643+
}
644+
645+
fn eight() -> u8 {
646+
Foo::C
647+
}
648+
```
649+
650+
When enum variants share the same name as associated types or consts, the enum variant candidate is given preference during resolution
651+
652+
653+
r[names.resolution.type-relative.stages.bodies.call-expressions]
654+
fully qualified call expressions:
655+
656+
```rust
657+
Type::assoc_func();
658+
```
659+
660+
- Call expressions
661+
- inherent associated functions
662+
- trait associated functions
663+
- methods via fqcs
664+
- No autoderefs are performed
665+
- static methods are included
666+
- lookup is done based on the type each implementation is for
667+
- what does this actually mean?
668+
669+
r[names.resolution.type-relative.stages.bodies.call-expressions.differences-from-method-resolution]
670+
671+
- https://doc.rust-lang.org/reference/expressions/method-call-expr.html
672+
673+
r[names.resolution.type-relative.stages.bodies.call-expressions.candidate-selection]
674+
675+
- https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls
676+
677+
Similar to method resolution, we look at all impls applicable for Type. Where
678+
"all impls applicable" is a mess.
679+
680+
- we only consider trait items for <_> but also consider - and prefer - inherent impls if the self type is not an infer var
681+
- This is necessary because otherwise there would be no way to refer to inherent associated items, we lack a disambiguation syntax in their favor.
682+
683+
```rust
684+
struct Foo;
685+
impl Foo {
686+
fn overlap(x: Foo) {
687+
println!("inherent");
688+
}
689+
}
690+
691+
trait Trait: Sized {
692+
fn overlap(x: Self) {
693+
println!("trait");
694+
}
695+
}
696+
impl Trait for Foo {}
697+
698+
fn main() {
699+
<_>::overlap(Foo); // trait
700+
<Foo>::overlap(Foo); // inherent
701+
}
702+
```
703+
704+
consider the following:
705+
706+
```rust
707+
struct Foo;
708+
impl Foo {
709+
fn inherent_func() {}
710+
}
711+
712+
trait Trait: Sized {
713+
fn trait_method() -> Self {
714+
todo!();
715+
}
716+
}
717+
impl Trait for Foo {}
718+
719+
fn main() {
720+
//<_>::inherent_func(); // ERROR: unable to get the assoc item
721+
//<_>::trait_method(); // ERROR: chose trait method, unable to infer the self type
722+
let _: Foo = <_>::trait_method(); // OK
723+
}
724+
```
725+
726+
- as types and traits are in the same namespace, their disambiguation is only relevant for inherent methods of trait objects without dyn i think
727+
- candidate preference is a mess, the trait candidate for dyn Trait gets treated as an inherent candidate instead of a trait candidate wrt to candidate preference
728+
729+
```rust
730+
trait Trait {
731+
fn assoc(&self) {
732+
println!("trait");
733+
}
734+
}
735+
impl Trait for i32 {}
736+
impl dyn Trait {
737+
fn assoc(&self) {
738+
println!("inherent");
739+
}
740+
}
741+
742+
fn main() {
743+
let x: &dyn Trait = &1;
744+
Trait::assoc(x); // trait
745+
<Trait>::assoc(x); // ambiguous
746+
<Trait as Trait>::assoc(x); // trait
747+
x.assoc(); // ambiguous
748+
}
749+
```
750+
751+
struct literals?
752+
753+
https://github.com/rust-lang/rust/blob/main/compiler/rustc_hir_typeck/src/method/mod.rs#L494
754+
https://github.com/rust-lang/rust/blob/main/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs#L295-L299
755+
https://github.com/rust-lang/rust/blob/main/compiler/rustc_resolve/src/late.rs#L475-L490
756+
https://github.com/rust-lang/rust/blob/main/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs#L1371
757+
- If you chase down where `QPath::TypeRelative` gets constructed you primarily
758+
end up at the callers of `lower_qpath`
759+
- lower_pat_mut for PatKinds TupleStruct, Path, and Struct
563760

564761
[AST]: glossary.ast
565762
[Builtin attributes]: ./preludes.md#r-names.preludes.lang

0 commit comments

Comments
 (0)