1616use std:: ops:: Index ;
1717use std:: sync:: Arc ;
1818
19- use chalk_ir:: { cast:: Cast , ConstValue , DebruijnIndex , Mutability , Safety , Scalar , TypeFlags } ;
19+ use chalk_ir:: { cast:: Cast , DebruijnIndex , Mutability , Safety , Scalar , TypeFlags } ;
2020use either:: Either ;
2121use hir_def:: {
2222 body:: Body ,
@@ -37,10 +37,10 @@ use rustc_hash::{FxHashMap, FxHashSet};
3737use stdx:: { always, never} ;
3838
3939use crate :: {
40- db:: HirDatabase , fold_tys, fold_tys_and_consts , infer:: coerce:: CoerceMany ,
41- lower :: ImplTraitLoweringMode , static_lifetime, to_assoc_type_id, AliasEq , AliasTy , Const ,
42- DomainGoal , GenericArg , Goal , ImplTraitId , InEnvironment , Interner , ProjectionTy , RpitId ,
43- Substitution , TraitRef , Ty , TyBuilder , TyExt , TyKind ,
40+ db:: HirDatabase , fold_tys, infer:: coerce:: CoerceMany , lower :: ImplTraitLoweringMode ,
41+ static_lifetime, to_assoc_type_id, AliasEq , AliasTy , DomainGoal , GenericArg , Goal , ImplTraitId ,
42+ InEnvironment , Interner , ProjectionTy , RpitId , Substitution , TraitRef , Ty , TyBuilder , TyExt ,
43+ TyKind ,
4444} ;
4545
4646// This lint has a false positive here. See the link below for details.
@@ -744,43 +744,13 @@ impl<'a> InferenceContext<'a> {
744744 self . result . standard_types . unknown . clone ( )
745745 }
746746
747- /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
748- fn insert_const_vars_shallow ( & mut self , c : Const ) -> Const {
749- let data = c. data ( Interner ) ;
750- match & data. value {
751- ConstValue :: Concrete ( cc) => match cc. interned {
752- crate :: ConstScalar :: Unknown => self . table . new_const_var ( data. ty . clone ( ) ) ,
753- _ => c,
754- } ,
755- _ => c,
756- }
757- }
758-
759747 /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
760748 fn insert_type_vars_shallow ( & mut self , ty : Ty ) -> Ty {
761- match ty. kind ( Interner ) {
762- TyKind :: Error => self . table . new_type_var ( ) ,
763- TyKind :: InferenceVar ( ..) => {
764- let ty_resolved = self . resolve_ty_shallow ( & ty) ;
765- if ty_resolved. is_unknown ( ) {
766- self . table . new_type_var ( )
767- } else {
768- ty
769- }
770- }
771- _ => ty,
772- }
749+ self . table . insert_type_vars_shallow ( ty)
773750 }
774751
775752 fn insert_type_vars ( & mut self , ty : Ty ) -> Ty {
776- fold_tys_and_consts (
777- ty,
778- |x, _| match x {
779- Either :: Left ( ty) => Either :: Left ( self . insert_type_vars_shallow ( ty) ) ,
780- Either :: Right ( c) => Either :: Right ( self . insert_const_vars_shallow ( c) ) ,
781- } ,
782- DebruijnIndex :: INNERMOST ,
783- )
753+ self . table . insert_type_vars ( ty)
784754 }
785755
786756 fn push_obligation ( & mut self , o : DomainGoal ) {
@@ -850,8 +820,6 @@ impl<'a> InferenceContext<'a> {
850820 None => return ( self . err_ty ( ) , None ) ,
851821 } ;
852822 let ctx = crate :: lower:: TyLoweringContext :: new ( self . db , & self . resolver ) ;
853- // FIXME: this should resolve assoc items as well, see this example:
854- // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
855823 let ( resolution, unresolved) = if value_ns {
856824 match self . resolver . resolve_path_in_value_ns ( self . db . upcast ( ) , path) {
857825 Some ( ResolveValueResult :: ValueNs ( value) ) => match value {
@@ -905,8 +873,68 @@ impl<'a> InferenceContext<'a> {
905873 TypeNs :: SelfType ( impl_id) => {
906874 let generics = crate :: utils:: generics ( self . db . upcast ( ) , impl_id. into ( ) ) ;
907875 let substs = generics. placeholder_subst ( self . db ) ;
908- let ty = self . db . impl_self_ty ( impl_id) . substitute ( Interner , & substs) ;
909- self . resolve_variant_on_alias ( ty, unresolved, mod_path)
876+ let mut ty = self . db . impl_self_ty ( impl_id) . substitute ( Interner , & substs) ;
877+
878+ let Some ( mut remaining_idx) = unresolved else {
879+ return self . resolve_variant_on_alias ( ty, None , mod_path) ;
880+ } ;
881+
882+ let mut remaining_segments = path. segments ( ) . skip ( remaining_idx) ;
883+
884+ // We need to try resolving unresolved segments one by one because each may resolve
885+ // to a projection, which `TyLoweringContext` cannot handle on its own.
886+ while !remaining_segments. is_empty ( ) {
887+ let resolved_segment = path. segments ( ) . get ( remaining_idx - 1 ) . unwrap ( ) ;
888+ let current_segment = remaining_segments. take ( 1 ) ;
889+
890+ // If we can resolve to an enum variant, it takes priority over associated type
891+ // of the same name.
892+ if let Some ( ( AdtId :: EnumId ( id) , _) ) = ty. as_adt ( ) {
893+ let enum_data = self . db . enum_data ( id) ;
894+ let name = current_segment. first ( ) . unwrap ( ) . name ;
895+ if let Some ( local_id) = enum_data. variant ( name) {
896+ let variant = EnumVariantId { parent : id, local_id } ;
897+ return if remaining_segments. len ( ) == 1 {
898+ ( ty, Some ( variant. into ( ) ) )
899+ } else {
900+ // We still have unresolved paths, but enum variants never have
901+ // associated types!
902+ ( self . err_ty ( ) , None )
903+ } ;
904+ }
905+ }
906+
907+ // `lower_partly_resolved_path()` returns `None` as type namespace unless
908+ // `remaining_segments` is empty, which is never the case here. We don't know
909+ // which namespace the new `ty` is in until normalized anyway.
910+ ( ty, _) = ctx. lower_partly_resolved_path (
911+ resolution,
912+ resolved_segment,
913+ current_segment,
914+ false ,
915+ ) ;
916+
917+ ty = self . table . insert_type_vars ( ty) ;
918+ ty = self . table . normalize_associated_types_in ( ty) ;
919+ ty = self . table . resolve_ty_shallow ( & ty) ;
920+ if ty. is_unknown ( ) {
921+ return ( self . err_ty ( ) , None ) ;
922+ }
923+
924+ // FIXME(inherent_associated_types): update `resolution` based on `ty` here.
925+ remaining_idx += 1 ;
926+ remaining_segments = remaining_segments. skip ( 1 ) ;
927+ }
928+
929+ let variant = ty. as_adt ( ) . and_then ( |( id, _) | match id {
930+ AdtId :: StructId ( s) => Some ( VariantId :: StructId ( s) ) ,
931+ AdtId :: UnionId ( u) => Some ( VariantId :: UnionId ( u) ) ,
932+ AdtId :: EnumId ( _) => {
933+ // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
934+ None
935+ }
936+ } ) ;
937+ ( ty, variant)
910938 }
911939 TypeNs :: TypeAliasId ( it) => {
912940 let container = it. lookup ( self . db . upcast ( ) ) . container ;
0 commit comments