Compare commits
5 Commits
david/fix-
...
david/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3d12c4aac | ||
|
|
1af318534a | ||
|
|
553e568624 | ||
|
|
cdef3f5ab8 | ||
|
|
6178822427 |
@@ -8,13 +8,12 @@ use crate::symbols::{QueryPattern, SymbolInfo, symbols_for_file_global_only};
|
||||
///
|
||||
/// Returns symbols from all files in the workspace and dependencies, filtered
|
||||
/// by the query.
|
||||
pub fn all_symbols<'db>(db: &'db dyn Db, query: &str) -> Vec<AllSymbolInfo<'db>> {
|
||||
pub fn all_symbols<'db>(db: &'db dyn Db, query: &QueryPattern) -> Vec<AllSymbolInfo<'db>> {
|
||||
// If the query is empty, return immediately to avoid expensive file scanning
|
||||
if query.is_empty() {
|
||||
if query.will_match_everything() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let query = QueryPattern::new(query);
|
||||
let results = std::sync::Mutex::new(Vec::new());
|
||||
{
|
||||
let modules = all_modules(db);
|
||||
@@ -144,7 +143,7 @@ ABCDEFGHIJKLMNOP = 'https://api.example.com'
|
||||
|
||||
impl CursorTest {
|
||||
fn all_symbols(&self, query: &str) -> String {
|
||||
let symbols = all_symbols(&self.db, query);
|
||||
let symbols = all_symbols(&self.db, &QueryPattern::new(query));
|
||||
|
||||
if symbols.is_empty() {
|
||||
return "No symbols found".to_string();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -67,6 +67,16 @@ impl QueryPattern {
|
||||
symbol_name.contains(&self.original)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true when it is known that this pattern will return `true` for
|
||||
/// all inputs given to `QueryPattern::is_match_symbol_name`.
|
||||
///
|
||||
/// This will never return `true` incorrectly, but it may return `false`
|
||||
/// incorrectly. That is, it's possible that this query will match all
|
||||
/// inputs but this still returns `false`.
|
||||
pub fn will_match_everything(&self) -> bool {
|
||||
self.re.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for QueryPattern {
|
||||
|
||||
@@ -389,9 +389,8 @@ ListOrTupleLegacy = Union[list[T], tuple[T, ...]]
|
||||
MyCallable = Callable[P, T]
|
||||
AnnotatedType = Annotated[T, "tag"]
|
||||
|
||||
# TODO: Consider displaying this as `<class 'list[T]'>`, … instead? (and similar for some others below)
|
||||
reveal_type(MyList) # revealed: <class 'list[typing.TypeVar]'>
|
||||
reveal_type(MyDict) # revealed: <class 'dict[typing.TypeVar, typing.TypeVar]'>
|
||||
reveal_type(MyList) # revealed: <class 'list[T]'>
|
||||
reveal_type(MyDict) # revealed: <class 'dict[T, U]'>
|
||||
reveal_type(MyType) # revealed: GenericAlias
|
||||
reveal_type(IntAndType) # revealed: <class 'tuple[int, typing.TypeVar]'>
|
||||
reveal_type(Pair) # revealed: <class 'tuple[typing.TypeVar, typing.TypeVar]'>
|
||||
@@ -496,9 +495,9 @@ def _(
|
||||
my_callable: MyCallable,
|
||||
):
|
||||
# TODO: Should be `list[Unknown]`
|
||||
reveal_type(my_list) # revealed: list[typing.TypeVar]
|
||||
reveal_type(my_list) # revealed: list[T]
|
||||
# TODO: Should be `dict[Unknown, Unknown]`
|
||||
reveal_type(my_dict) # revealed: dict[typing.TypeVar, typing.TypeVar]
|
||||
reveal_type(my_dict) # revealed: dict[T, U]
|
||||
# TODO: Should be `(...) -> Unknown`
|
||||
reveal_type(my_callable) # revealed: (...) -> typing.TypeVar
|
||||
```
|
||||
@@ -523,7 +522,7 @@ reveal_mro(Derived1)
|
||||
GenericBaseAlias = GenericBase[T]
|
||||
|
||||
# TODO: No error here
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `<class 'GenericBase[typing.TypeVar]'>` with no `__class_getitem__` method"
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `<class 'GenericBase[T]'>` with no `__class_getitem__` method"
|
||||
class Derived2(GenericBaseAlias[int]):
|
||||
pass
|
||||
```
|
||||
|
||||
@@ -28,6 +28,10 @@ error[unresolved-import]: Cannot resolve imported module `.does_not_exist.foo.ba
|
||||
2 |
|
||||
3 | stat = add(10, 15)
|
||||
|
|
||||
info: Searched in the following paths during module resolution:
|
||||
info: 1. /src (first-party code)
|
||||
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
||||
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
||||
info: rule `unresolved-import` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
@@ -28,6 +28,10 @@ error[unresolved-import]: Cannot resolve imported module `.does_not_exist`
|
||||
2 |
|
||||
3 | stat = add(10, 15)
|
||||
|
|
||||
info: Searched in the following paths during module resolution:
|
||||
info: 1. /src (first-party code)
|
||||
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
||||
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
||||
info: rule `unresolved-import` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
@@ -40,6 +40,10 @@ error[unresolved-import]: Cannot resolve imported module `....foo`
|
||||
2 |
|
||||
3 | stat = add(10, 15)
|
||||
|
|
||||
info: Searched in the following paths during module resolution:
|
||||
info: 1. /src (first-party code)
|
||||
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
|
||||
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
|
||||
info: rule `unresolved-import` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
@@ -296,7 +296,7 @@ impl ModuleName {
|
||||
}
|
||||
|
||||
/// Computes the absolute module name from the LHS components of `from LHS import RHS`
|
||||
pub(crate) fn from_identifier_parts(
|
||||
pub fn from_identifier_parts(
|
||||
db: &dyn Db,
|
||||
importing_file: File,
|
||||
module: Option<&str>,
|
||||
|
||||
@@ -91,11 +91,7 @@ impl<'db> SemanticModel<'db> {
|
||||
}
|
||||
|
||||
/// Returns completions for symbols available in a `from module import <CURSOR>` context.
|
||||
pub fn from_import_completions(
|
||||
&self,
|
||||
import: &ast::StmtImportFrom,
|
||||
_name: Option<usize>,
|
||||
) -> Vec<Completion<'db>> {
|
||||
pub fn from_import_completions(&self, import: &ast::StmtImportFrom) -> Vec<Completion<'db>> {
|
||||
let module_name = match ModuleName::from_import_statement(self.db, self.file, import) {
|
||||
Ok(module_name) => module_name,
|
||||
Err(err) => {
|
||||
@@ -110,69 +106,8 @@ impl<'db> SemanticModel<'db> {
|
||||
self.module_completions(&module_name)
|
||||
}
|
||||
|
||||
/// Returns completions only for submodules for the module
|
||||
/// identified by `name` in `import`.
|
||||
///
|
||||
/// For example, `import re, os.<CURSOR>, zlib`.
|
||||
pub fn import_submodule_completions(
|
||||
&self,
|
||||
import: &ast::StmtImport,
|
||||
name: usize,
|
||||
) -> Vec<Completion<'db>> {
|
||||
let module_ident = &import.names[name].name;
|
||||
let Some((parent_ident, _)) = module_ident.rsplit_once('.') else {
|
||||
return vec![];
|
||||
};
|
||||
let module_name =
|
||||
match ModuleName::from_identifier_parts(self.db, self.file, Some(parent_ident), 0) {
|
||||
Ok(module_name) => module_name,
|
||||
Err(err) => {
|
||||
tracing::debug!(
|
||||
"Could not extract module name from `{module:?}`: {err:?}",
|
||||
module = module_ident,
|
||||
);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
self.import_submodule_completions_for_name(&module_name)
|
||||
}
|
||||
|
||||
/// Returns completions only for submodules for the module
|
||||
/// used in a `from module import attribute` statement.
|
||||
///
|
||||
/// For example, `from os.<CURSOR>`.
|
||||
pub fn from_import_submodule_completions(
|
||||
&self,
|
||||
import: &ast::StmtImportFrom,
|
||||
) -> Vec<Completion<'db>> {
|
||||
let level = import.level;
|
||||
let Some(module_ident) = import.module.as_deref() else {
|
||||
return vec![];
|
||||
};
|
||||
let Some((parent_ident, _)) = module_ident.rsplit_once('.') else {
|
||||
return vec![];
|
||||
};
|
||||
let module_name = match ModuleName::from_identifier_parts(
|
||||
self.db,
|
||||
self.file,
|
||||
Some(parent_ident),
|
||||
level,
|
||||
) {
|
||||
Ok(module_name) => module_name,
|
||||
Err(err) => {
|
||||
tracing::debug!(
|
||||
"Could not extract module name from `{module:?}` with level {level}: {err:?}",
|
||||
module = import.module,
|
||||
level = import.level,
|
||||
);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
self.import_submodule_completions_for_name(&module_name)
|
||||
}
|
||||
|
||||
/// Returns submodule-only completions for the given module.
|
||||
fn import_submodule_completions_for_name(
|
||||
pub fn import_submodule_completions_for_name(
|
||||
&self,
|
||||
module_name: &ModuleName,
|
||||
) -> Vec<Completion<'db>> {
|
||||
|
||||
@@ -7197,6 +7197,8 @@ impl<'db> Type<'db> {
|
||||
instance.apply_type_mapping_impl(db, type_mapping, tcx, visitor)
|
||||
},
|
||||
|
||||
Type::NewTypeInstance(_) if matches!(type_mapping, TypeMapping::BindLegacyTypevars(_)) => self,
|
||||
|
||||
Type::NewTypeInstance(newtype) => visitor.visit(self, || {
|
||||
Type::NewTypeInstance(newtype.map_base_class_type(db, |class_type| {
|
||||
class_type.apply_type_mapping_impl(db, type_mapping, tcx, visitor)
|
||||
@@ -7275,6 +7277,8 @@ impl<'db> Type<'db> {
|
||||
// TODO(jelle): Materialize should be handled differently, since TypeIs is invariant
|
||||
Type::TypeIs(type_is) => type_is.with_type(db, type_is.return_type(db).apply_type_mapping(db, type_mapping, tcx)),
|
||||
|
||||
Type::TypeAlias(_) if matches!(type_mapping, TypeMapping::BindLegacyTypevars(_)) => self,
|
||||
|
||||
Type::TypeAlias(alias) => {
|
||||
// Do not call `value_type` here. `value_type` does the specialization internally, so `apply_type_mapping` is performed without `visitor` inheritance.
|
||||
// In the case of recursive type aliases, this leads to infinite recursion.
|
||||
|
||||
@@ -101,14 +101,14 @@ use crate::types::typed_dict::{
|
||||
};
|
||||
use crate::types::visitor::any_over_type;
|
||||
use crate::types::{
|
||||
CallDunderError, CallableBinding, CallableType, ClassLiteral, ClassType, DataclassParams,
|
||||
DynamicType, InternedType, IntersectionBuilder, IntersectionType, KnownClass,
|
||||
BindingContext, CallDunderError, CallableBinding, CallableType, ClassLiteral, ClassType,
|
||||
DataclassParams, DynamicType, InternedType, IntersectionBuilder, IntersectionType, KnownClass,
|
||||
KnownInstanceType, LintDiagnosticGuard, MemberLookupPolicy, MetaclassCandidate,
|
||||
PEP695TypeAliasType, Parameter, ParameterForm, Parameters, SpecialFormType, SubclassOfType,
|
||||
TrackedConstraintSet, Truthiness, Type, TypeAliasType, TypeAndQualifiers, TypeContext,
|
||||
TypeQualifiers, TypeVarBoundOrConstraintsEvaluation, TypeVarDefaultEvaluation, TypeVarIdentity,
|
||||
TypeVarInstance, TypeVarKind, TypeVarVariance, TypedDictType, UnionBuilder, UnionType,
|
||||
UnionTypeInstance, binding_type, todo_type,
|
||||
TypeMapping, TypeQualifiers, TypeVarBoundOrConstraintsEvaluation, TypeVarDefaultEvaluation,
|
||||
TypeVarIdentity, TypeVarInstance, TypeVarKind, TypeVarVariance, TypedDictType, UnionBuilder,
|
||||
UnionType, UnionTypeInstance, binding_type, todo_type,
|
||||
};
|
||||
use crate::types::{ClassBase, add_inferred_python_version_hint_to_diagnostic};
|
||||
use crate::unpack::{EvaluationMode, UnpackPosition};
|
||||
@@ -5803,6 +5803,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
".".repeat(level as usize),
|
||||
module.unwrap_or_default()
|
||||
));
|
||||
|
||||
if level == 0 {
|
||||
if let Some(module_name) = module.and_then(ModuleName::new) {
|
||||
let program = Program::get(self.db());
|
||||
@@ -5831,39 +5832,39 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add search paths information to the diagnostic
|
||||
// Use the same search paths function that is used in actual module resolution
|
||||
let verbose = self.db().verbose();
|
||||
let search_paths = search_paths(self.db(), ModuleResolveMode::StubsAllowed);
|
||||
|
||||
diagnostic.info(format_args!(
|
||||
"Searched in the following paths during module resolution:"
|
||||
));
|
||||
|
||||
let mut search_paths = search_paths.enumerate();
|
||||
|
||||
while let Some((index, path)) = search_paths.next() {
|
||||
if index > 4 && !verbose {
|
||||
let more = search_paths.count() + 1;
|
||||
diagnostic.info(format_args!(
|
||||
" ... and {more} more paths. Run with `-v` to see all paths."
|
||||
));
|
||||
break;
|
||||
}
|
||||
diagnostic.info(format_args!(
|
||||
" {}. {} ({})",
|
||||
index + 1,
|
||||
path,
|
||||
path.describe_kind()
|
||||
));
|
||||
}
|
||||
|
||||
diagnostic.info(
|
||||
"make sure your Python environment is properly configured: \
|
||||
https://docs.astral.sh/ty/modules/#python-environment",
|
||||
);
|
||||
}
|
||||
|
||||
// Add search paths information to the diagnostic
|
||||
// Use the same search paths function that is used in actual module resolution
|
||||
let verbose = self.db().verbose();
|
||||
let search_paths = search_paths(self.db(), ModuleResolveMode::StubsAllowed);
|
||||
|
||||
diagnostic.info(format_args!(
|
||||
"Searched in the following paths during module resolution:"
|
||||
));
|
||||
|
||||
let mut search_paths = search_paths.enumerate();
|
||||
|
||||
while let Some((index, path)) = search_paths.next() {
|
||||
if index > 4 && !verbose {
|
||||
let more = search_paths.count() + 1;
|
||||
diagnostic.info(format_args!(
|
||||
" ... and {more} more paths. Run with `-v` to see all paths."
|
||||
));
|
||||
break;
|
||||
}
|
||||
diagnostic.info(format_args!(
|
||||
" {}. {} ({})",
|
||||
index + 1,
|
||||
path,
|
||||
path.describe_kind()
|
||||
));
|
||||
}
|
||||
|
||||
diagnostic.info(
|
||||
"make sure your Python environment is properly configured: \
|
||||
https://docs.astral.sh/ty/modules/#python-environment",
|
||||
);
|
||||
}
|
||||
|
||||
fn infer_import_definition(
|
||||
@@ -11045,6 +11046,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
value_ty,
|
||||
generic_context,
|
||||
specialize,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11069,6 +11071,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
value_ty,
|
||||
generic_context,
|
||||
specialize,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11078,12 +11081,30 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
value_ty: Type<'db>,
|
||||
generic_context: GenericContext<'db>,
|
||||
specialize: impl FnOnce(&[Option<Type<'db>>]) -> Type<'db>,
|
||||
bind_legacy_typevars: bool,
|
||||
) -> Type<'db> {
|
||||
let slice_node = subscript.slice.as_ref();
|
||||
|
||||
let db = self.db();
|
||||
let do_bind_legacy_typevars = |ty: Type<'db>| {
|
||||
if bind_legacy_typevars {
|
||||
ty.apply_type_mapping(
|
||||
db,
|
||||
&TypeMapping::BindLegacyTypevars(BindingContext::Synthetic),
|
||||
TypeContext::default(),
|
||||
)
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
};
|
||||
|
||||
let call_argument_types = match slice_node {
|
||||
ast::Expr::Tuple(tuple) => {
|
||||
let arguments = CallArguments::positional(
|
||||
tuple.elts.iter().map(|elt| self.infer_type_expression(elt)),
|
||||
tuple
|
||||
.elts
|
||||
.iter()
|
||||
.map(|elt| do_bind_legacy_typevars(self.infer_type_expression(elt))),
|
||||
);
|
||||
self.store_expression_type(
|
||||
slice_node,
|
||||
@@ -11091,8 +11112,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
);
|
||||
arguments
|
||||
}
|
||||
_ => CallArguments::positional([self.infer_type_expression(slice_node)]),
|
||||
_ => CallArguments::positional([do_bind_legacy_typevars(
|
||||
self.infer_type_expression(slice_node),
|
||||
)]),
|
||||
};
|
||||
|
||||
let binding = Binding::single(value_ty, generic_context.signature(self.db()));
|
||||
let bindings = match Bindings::from(binding)
|
||||
.match_parameters(self.db(), &call_argument_types)
|
||||
|
||||
Reference in New Issue
Block a user