@@ -865,6 +865,14 @@ impl<'db> TypeInferenceBuilder<'db> {
865
865
self . types . bindings . insert ( definition, inferred_ty) ;
866
866
}
867
867
868
+ fn add_unknown_declaration_with_binding (
869
+ & mut self ,
870
+ node : AnyNodeRef ,
871
+ definition : Definition < ' db > ,
872
+ ) {
873
+ self . add_declaration_with_binding ( node, definition, Type :: Unknown , Type :: Unknown ) ;
874
+ }
875
+
868
876
fn infer_module ( & mut self , module : & ast:: ModModule ) {
869
877
self . infer_body ( & module. body ) ;
870
878
}
@@ -2121,24 +2129,14 @@ impl<'db> TypeInferenceBuilder<'db> {
2121
2129
// The name of the module being imported
2122
2130
let Some ( full_module_name) = ModuleName :: new ( name) else {
2123
2131
tracing:: debug!( "Failed to resolve import due to invalid syntax" ) ;
2124
- self . add_declaration_with_binding (
2125
- alias. into ( ) ,
2126
- definition,
2127
- Type :: Unknown ,
2128
- Type :: Unknown ,
2129
- ) ;
2132
+ self . add_unknown_declaration_with_binding ( alias. into ( ) , definition) ;
2130
2133
return ;
2131
2134
} ;
2132
2135
2133
2136
// Resolve the module being imported.
2134
2137
let Some ( full_module_ty) = self . module_ty_from_name ( & full_module_name) else {
2135
2138
self . diagnostics . add_unresolved_module ( alias, 0 , Some ( name) ) ;
2136
- self . add_declaration_with_binding (
2137
- alias. into ( ) ,
2138
- definition,
2139
- Type :: Unknown ,
2140
- Type :: Unknown ,
2141
- ) ;
2139
+ self . add_unknown_declaration_with_binding ( alias. into ( ) , definition) ;
2142
2140
return ;
2143
2141
} ;
2144
2142
@@ -2152,11 +2150,11 @@ impl<'db> TypeInferenceBuilder<'db> {
2152
2150
// parent package of that module.
2153
2151
let topmost_parent_name =
2154
2152
ModuleName :: new ( full_module_name. components ( ) . next ( ) . unwrap ( ) ) . unwrap ( ) ;
2155
- if let Some ( topmost_parent_ty) = self . module_ty_from_name ( & topmost_parent_name) {
2156
- topmost_parent_ty
2157
- } else {
2158
- Type :: Unknown
2159
- }
2153
+ let Some ( topmost_parent_ty) = self . module_ty_from_name ( & topmost_parent_name) else {
2154
+ self . add_unknown_declaration_with_binding ( alias . into ( ) , definition ) ;
2155
+ return ;
2156
+ } ;
2157
+ topmost_parent_ty
2160
2158
} else {
2161
2159
// If there's no `as` clause and the imported module isn't nested, then the imported
2162
2160
// module _is_ what we bind into the current scope.
@@ -2243,12 +2241,6 @@ impl<'db> TypeInferenceBuilder<'db> {
2243
2241
// TODO:
2244
2242
// - Absolute `*` imports (`from collections import *`)
2245
2243
// - Relative `*` imports (`from ...foo import *`)
2246
- // - Submodule imports (`from collections import abc`,
2247
- // where `abc` is a submodule of the `collections` package)
2248
- //
2249
- // For the last item, see the currently skipped tests
2250
- // `follow_relative_import_bare_to_module()` and
2251
- // `follow_nonexistent_import_bare_to_module()`.
2252
2244
let ast:: StmtImportFrom { module, level, .. } = import_from;
2253
2245
let module = module. as_deref ( ) ;
2254
2246
@@ -2271,46 +2263,13 @@ impl<'db> TypeInferenceBuilder<'db> {
2271
2263
. ok_or ( ModuleNameResolutionError :: InvalidSyntax )
2272
2264
} ;
2273
2265
2274
- let ty = match module_name {
2275
- Ok ( module_name) => {
2276
- if let Some ( module_ty) = self . module_ty_from_name ( & module_name) {
2277
- let ast:: Alias {
2278
- range : _,
2279
- name,
2280
- asname : _,
2281
- } = alias;
2282
-
2283
- match module_ty. member ( self . db , & ast:: name:: Name :: new ( & name. id ) ) {
2284
- Symbol :: Type ( ty, boundness) => {
2285
- if boundness == Boundness :: PossiblyUnbound {
2286
- self . diagnostics . add_lint (
2287
- & POSSIBLY_UNBOUND_IMPORT ,
2288
- AnyNodeRef :: Alias ( alias) ,
2289
- format_args ! ( "Member `{name}` of module `{module_name}` is possibly unbound" , ) ,
2290
- ) ;
2291
- }
2292
-
2293
- ty
2294
- }
2295
- Symbol :: Unbound => {
2296
- self . diagnostics . add_lint (
2297
- & UNRESOLVED_IMPORT ,
2298
- AnyNodeRef :: Alias ( alias) ,
2299
- format_args ! ( "Module `{module_name}` has no member `{name}`" , ) ,
2300
- ) ;
2301
- Type :: Unknown
2302
- }
2303
- }
2304
- } else {
2305
- self . diagnostics
2306
- . add_unresolved_module ( import_from, * level, module) ;
2307
- Type :: Unknown
2308
- }
2309
- }
2266
+ let module_name = match module_name {
2267
+ Ok ( module_name) => module_name,
2310
2268
Err ( ModuleNameResolutionError :: InvalidSyntax ) => {
2311
2269
tracing:: debug!( "Failed to resolve import due to invalid syntax" ) ;
2312
2270
// Invalid syntax diagnostics are emitted elsewhere.
2313
- Type :: Unknown
2271
+ self . add_unknown_declaration_with_binding ( alias. into ( ) , definition) ;
2272
+ return ;
2314
2273
}
2315
2274
Err ( ModuleNameResolutionError :: TooManyDots ) => {
2316
2275
tracing:: debug!(
@@ -2319,7 +2278,8 @@ impl<'db> TypeInferenceBuilder<'db> {
2319
2278
) ;
2320
2279
self . diagnostics
2321
2280
. add_unresolved_module ( import_from, * level, module) ;
2322
- Type :: Unknown
2281
+ self . add_unknown_declaration_with_binding ( alias. into ( ) , definition) ;
2282
+ return ;
2323
2283
}
2324
2284
Err ( ModuleNameResolutionError :: UnknownCurrentModule ) => {
2325
2285
tracing:: debug!(
@@ -2329,10 +2289,72 @@ impl<'db> TypeInferenceBuilder<'db> {
2329
2289
) ;
2330
2290
self . diagnostics
2331
2291
. add_unresolved_module ( import_from, * level, module) ;
2332
- Type :: Unknown
2292
+ self . add_unknown_declaration_with_binding ( alias. into ( ) , definition) ;
2293
+ return ;
2294
+ }
2295
+ } ;
2296
+
2297
+ let Some ( module_ty) = self . module_ty_from_name ( & module_name) else {
2298
+ self . diagnostics
2299
+ . add_unresolved_module ( import_from, * level, module) ;
2300
+ self . add_unknown_declaration_with_binding ( alias. into ( ) , definition) ;
2301
+ return ;
2302
+ } ;
2303
+
2304
+ let ast:: Alias {
2305
+ range : _,
2306
+ name,
2307
+ asname : _,
2308
+ } = alias;
2309
+
2310
+ // Check if the symbol being imported is a submodule. This won't get handled by the
2311
+ // `Type::member` call below because it relies on the semantic index's `imported_modules`
2312
+ // set. The semantic index does not include information about `from...import` statements
2313
+ // because there are two things it cannot determine while only inspecting the content of
2314
+ // the current file:
2315
+ //
2316
+ // - whether the imported symbol is an attribute or submodule
2317
+ // - whether the containing file is in a module or a package (needed to correctly resolve
2318
+ // relative imports)
2319
+ //
2320
+ // The first would be solvable by making it a _potentially_ imported modules set. The
2321
+ // second is not.
2322
+ //
2323
+ // Regardless, for now, we sidestep all of that by repeating the submodule-or-attribute
2324
+ // check here when inferring types for a `from...import` statement.
2325
+ if let Some ( submodule_name) = ModuleName :: new ( name) {
2326
+ let mut full_submodule_name = module_name. clone ( ) ;
2327
+ full_submodule_name. extend ( & submodule_name) ;
2328
+ if let Some ( submodule_ty) = self . module_ty_from_name ( & full_submodule_name) {
2329
+ self . add_declaration_with_binding (
2330
+ alias. into ( ) ,
2331
+ definition,
2332
+ submodule_ty,
2333
+ submodule_ty,
2334
+ ) ;
2335
+ return ;
2333
2336
}
2337
+ }
2338
+
2339
+ // Otherwise load the requested attribute from the module.
2340
+ let Symbol :: Type ( ty, boundness) = module_ty. member ( self . db , name) else {
2341
+ self . diagnostics . add_lint (
2342
+ & UNRESOLVED_IMPORT ,
2343
+ AnyNodeRef :: Alias ( alias) ,
2344
+ format_args ! ( "Module `{module_name}` has no member `{name}`" , ) ,
2345
+ ) ;
2346
+ self . add_unknown_declaration_with_binding ( alias. into ( ) , definition) ;
2347
+ return ;
2334
2348
} ;
2335
2349
2350
+ if boundness == Boundness :: PossiblyUnbound {
2351
+ self . diagnostics . add_lint (
2352
+ & POSSIBLY_UNBOUND_IMPORT ,
2353
+ AnyNodeRef :: Alias ( alias) ,
2354
+ format_args ! ( "Member `{name}` of module `{module_name}` is possibly unbound" , ) ,
2355
+ ) ;
2356
+ }
2357
+
2336
2358
self . add_declaration_with_binding ( alias. into ( ) , definition, ty, ty) ;
2337
2359
}
2338
2360
0 commit comments