@@ -14,7 +14,7 @@ use crate::{
14
14
} ;
15
15
use either:: Either ;
16
16
use hir_def:: {
17
- AssocItemId , CallableDefId , ConstId , DefWithBodyId , FieldId , FunctionId , GenericDefId ,
17
+ AdtId , AssocItemId , CallableDefId , ConstId , DefWithBodyId , FieldId , FunctionId , GenericDefId ,
18
18
ItemContainerId , LocalFieldId , Lookup , ModuleDefId , StructId , TraitId , VariantId ,
19
19
expr_store:: {
20
20
Body , BodySourceMap , ExpressionStore , ExpressionStoreSourceMap , HygieneId ,
@@ -34,8 +34,8 @@ use hir_expand::{
34
34
name:: { AsName , Name } ,
35
35
} ;
36
36
use hir_ty:: {
37
- Adjustment , InferenceResult , Interner , Substitution , TraitEnvironment , Ty , TyExt , TyKind ,
38
- TyLoweringContext ,
37
+ Adjustment , AliasTy , InferenceResult , Interner , ProjectionTy , Substitution , TraitEnvironment ,
38
+ Ty , TyExt , TyKind , TyLoweringContext ,
39
39
diagnostics:: {
40
40
InsideUnsafeBlock , record_literal_missing_fields, record_pattern_missing_fields,
41
41
unsafe_operations,
@@ -47,6 +47,7 @@ use hir_ty::{
47
47
use intern:: sym;
48
48
use itertools:: Itertools ;
49
49
use smallvec:: SmallVec ;
50
+ use stdx:: never;
50
51
use syntax:: {
51
52
SyntaxKind , SyntaxNode , TextRange , TextSize ,
52
53
ast:: { self , AstNode , RangeItem , RangeOp } ,
@@ -791,6 +792,78 @@ impl SourceAnalyzer {
791
792
. map ( crate :: TypeParam :: from)
792
793
}
793
794
795
+ pub ( crate ) fn resolve_offset_of_field (
796
+ & self ,
797
+ db : & dyn HirDatabase ,
798
+ name_ref : & ast:: NameRef ,
799
+ ) -> Option < ( Either < crate :: Variant , crate :: Field > , GenericSubstitution ) > {
800
+ let offset_of_expr = ast:: OffsetOfExpr :: cast ( name_ref. syntax ( ) . parent ( ) ?) ?;
801
+ let container = offset_of_expr. ty ( ) ?;
802
+ let container = self . type_of_type ( db, & container) ?;
803
+
804
+ let trait_env = container. env ;
805
+ let mut container = Either :: Right ( container. ty ) ;
806
+ for field_name in offset_of_expr. fields ( ) {
807
+ if let Some (
808
+ TyKind :: Alias ( AliasTy :: Projection ( ProjectionTy { associated_ty_id, substitution } ) )
809
+ | TyKind :: AssociatedType ( associated_ty_id, substitution) ,
810
+ ) = container. as_ref ( ) . right ( ) . map ( |it| it. kind ( Interner ) )
811
+ {
812
+ let projection = ProjectionTy {
813
+ associated_ty_id : * associated_ty_id,
814
+ substitution : substitution. clone ( ) ,
815
+ } ;
816
+ container = Either :: Right ( db. normalize_projection ( projection, trait_env. clone ( ) ) ) ;
817
+ }
818
+ let handle_variants = |variant, subst : & Substitution , container : & mut _ | {
819
+ let fields = db. variant_fields ( variant) ;
820
+ let field = fields. field ( & field_name. as_name ( ) ) ?;
821
+ let field_types = db. field_types ( variant) ;
822
+ * container = Either :: Right ( field_types[ field] . clone ( ) . substitute ( Interner , subst) ) ;
823
+ let generic_def = match variant {
824
+ VariantId :: EnumVariantId ( it) => it. loc ( db) . parent . into ( ) ,
825
+ VariantId :: StructId ( it) => it. into ( ) ,
826
+ VariantId :: UnionId ( it) => it. into ( ) ,
827
+ } ;
828
+ Some ( (
829
+ Either :: Right ( Field { parent : variant. into ( ) , id : field } ) ,
830
+ generic_def,
831
+ subst. clone ( ) ,
832
+ ) )
833
+ } ;
834
+ let temp_ty = TyKind :: Error . intern ( Interner ) ;
835
+ let ( field_def, generic_def, subst) =
836
+ match std:: mem:: replace ( & mut container, Either :: Right ( temp_ty. clone ( ) ) ) {
837
+ Either :: Left ( ( variant_id, subst) ) => {
838
+ handle_variants ( VariantId :: from ( variant_id) , & subst, & mut container) ?
839
+ }
840
+ Either :: Right ( container_ty) => match container_ty. kind ( Interner ) {
841
+ TyKind :: Adt ( adt_id, subst) => match adt_id. 0 {
842
+ AdtId :: StructId ( id) => {
843
+ handle_variants ( id. into ( ) , subst, & mut container) ?
844
+ }
845
+ AdtId :: UnionId ( id) => {
846
+ handle_variants ( id. into ( ) , subst, & mut container) ?
847
+ }
848
+ AdtId :: EnumId ( id) => {
849
+ let variants = db. enum_variants ( id) ;
850
+ let variant = variants. variant ( & field_name. as_name ( ) ) ?;
851
+ container = Either :: Left ( ( variant, subst. clone ( ) ) ) ;
852
+ ( Either :: Left ( Variant { id : variant } ) , id. into ( ) , subst. clone ( ) )
853
+ }
854
+ } ,
855
+ _ => return None ,
856
+ } ,
857
+ } ;
858
+
859
+ if field_name. syntax ( ) . text_range ( ) == name_ref. syntax ( ) . text_range ( ) {
860
+ return Some ( ( field_def, GenericSubstitution :: new ( generic_def, subst, trait_env) ) ) ;
861
+ }
862
+ }
863
+ never ! ( "the `NameRef` is a child of the `OffsetOfExpr`, we should've visited it" ) ;
864
+ None
865
+ }
866
+
794
867
pub ( crate ) fn resolve_path (
795
868
& self ,
796
869
db : & dyn HirDatabase ,
0 commit comments