@@ -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 } ,
@@ -788,6 +789,78 @@ impl SourceAnalyzer {
788
789
. map ( crate :: TypeParam :: from)
789
790
}
790
791
792
+ pub ( crate ) fn resolve_offset_of_field (
793
+ & self ,
794
+ db : & dyn HirDatabase ,
795
+ name_ref : & ast:: NameRef ,
796
+ ) -> Option < ( Either < crate :: Variant , crate :: Field > , GenericSubstitution ) > {
797
+ let offset_of_expr = ast:: OffsetOfExpr :: cast ( name_ref. syntax ( ) . parent ( ) ?) ?;
798
+ let container = offset_of_expr. ty ( ) ?;
799
+ let container = self . type_of_type ( db, & container) ?;
800
+
801
+ let trait_env = container. env ;
802
+ let mut container = Either :: Right ( container. ty ) ;
803
+ for field_name in offset_of_expr. fields ( ) {
804
+ if let Some (
805
+ TyKind :: Alias ( AliasTy :: Projection ( ProjectionTy { associated_ty_id, substitution } ) )
806
+ | TyKind :: AssociatedType ( associated_ty_id, substitution) ,
807
+ ) = container. as_ref ( ) . right ( ) . map ( |it| it. kind ( Interner ) )
808
+ {
809
+ let projection = ProjectionTy {
810
+ associated_ty_id : * associated_ty_id,
811
+ substitution : substitution. clone ( ) ,
812
+ } ;
813
+ container = Either :: Right ( db. normalize_projection ( projection, trait_env. clone ( ) ) ) ;
814
+ }
815
+ let handle_variants = |variant, subst : & Substitution , container : & mut _ | {
816
+ let fields = db. variant_fields ( variant) ;
817
+ let field = fields. field ( & field_name. as_name ( ) ) ?;
818
+ let field_types = db. field_types ( variant) ;
819
+ * container = Either :: Right ( field_types[ field] . clone ( ) . substitute ( Interner , subst) ) ;
820
+ let generic_def = match variant {
821
+ VariantId :: EnumVariantId ( it) => it. loc ( db) . parent . into ( ) ,
822
+ VariantId :: StructId ( it) => it. into ( ) ,
823
+ VariantId :: UnionId ( it) => it. into ( ) ,
824
+ } ;
825
+ Some ( (
826
+ Either :: Right ( Field { parent : variant. into ( ) , id : field } ) ,
827
+ generic_def,
828
+ subst. clone ( ) ,
829
+ ) )
830
+ } ;
831
+ let temp_ty = TyKind :: Error . intern ( Interner ) ;
832
+ let ( field_def, generic_def, subst) =
833
+ match std:: mem:: replace ( & mut container, Either :: Right ( temp_ty. clone ( ) ) ) {
834
+ Either :: Left ( ( variant_id, subst) ) => {
835
+ handle_variants ( VariantId :: from ( variant_id) , & subst, & mut container) ?
836
+ }
837
+ Either :: Right ( container_ty) => match container_ty. kind ( Interner ) {
838
+ TyKind :: Adt ( adt_id, subst) => match adt_id. 0 {
839
+ AdtId :: StructId ( id) => {
840
+ handle_variants ( id. into ( ) , subst, & mut container) ?
841
+ }
842
+ AdtId :: UnionId ( id) => {
843
+ handle_variants ( id. into ( ) , subst, & mut container) ?
844
+ }
845
+ AdtId :: EnumId ( id) => {
846
+ let variants = db. enum_variants ( id) ;
847
+ let variant = variants. variant ( & field_name. as_name ( ) ) ?;
848
+ container = Either :: Left ( ( variant, subst. clone ( ) ) ) ;
849
+ ( Either :: Left ( Variant { id : variant } ) , id. into ( ) , subst. clone ( ) )
850
+ }
851
+ } ,
852
+ _ => return None ,
853
+ } ,
854
+ } ;
855
+
856
+ if field_name. syntax ( ) . text_range ( ) == name_ref. syntax ( ) . text_range ( ) {
857
+ return Some ( ( field_def, GenericSubstitution :: new ( generic_def, subst, trait_env) ) ) ;
858
+ }
859
+ }
860
+ never ! ( "the `NameRef` is a child of the `OffsetOfExpr`, we should've visited it" ) ;
861
+ None
862
+ }
863
+
791
864
pub ( crate ) fn resolve_path (
792
865
& self ,
793
866
db : & dyn HirDatabase ,
0 commit comments