diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 50109fd19488c9..b1f22a9d0ffa63 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -151,7 +151,7 @@ pub(crate) fn definitions_ty<'db>( } /// Unique ID for a type. -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum Type<'db> { /// the dynamic type: a statically-unknown set of values Any, @@ -159,7 +159,7 @@ pub enum Type<'db> { Never, /// unknown type (either no annotation, or some kind of type error) /// equivalent to Any, or possibly to object in strict mode - Unknown, + Unknown(UnknownTypeKind), /// name does not exist or is not bound to any value (this represents an error, but with some /// leniency options it could be silently resolved to Unknown in some cases) Unbound, @@ -189,10 +189,6 @@ impl<'db> Type<'db> { matches!(self, Type::Unbound) } - pub const fn is_unknown(&self) -> bool { - matches!(self, Type::Unknown) - } - pub const fn is_never(&self) -> bool { matches!(self, Type::Never) } @@ -207,18 +203,24 @@ impl<'db> Type<'db> { } } + /// Apply a function to the type (if it is a non-union); or, + /// if it is a union, apply the function to each element of the union + /// and build a new union from the result #[must_use] - pub fn replace_unbound_with(&self, db: &'db dyn Db, replacement: Type<'db>) -> Type<'db> { + pub fn recursive_transform( + self, + db: &'db dyn Db, + mut transform_fn: impl FnMut(Type<'db>) -> Type<'db>, + ) -> Self { match self { - Type::Unbound => replacement, Type::Union(union) => union .elements(db) .into_iter() .fold(UnionBuilder::new(db), |builder, ty| { - builder.add(ty.replace_unbound_with(db, replacement)) + builder.add(transform_fn(ty)) }) .build(), - ty => *ty, + ty => transform_fn(ty), } } @@ -241,23 +243,23 @@ impl<'db> Type<'db> { Type::Any => Type::Any, Type::Never => { // TODO: attribute lookup on Never type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } - Type::Unknown => Type::Unknown, + Type::Unknown(kind) => Type::Unknown(*kind), Type::Unbound => Type::Unbound, Type::None => { // TODO: attribute lookup on None type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } Type::Function(_) => { // TODO: attribute lookup on function type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } Type::Module(file) => global_symbol_ty_by_name(db, *file, name), Type::Class(class) => class.class_member(db, name), Type::Instance(_) => { // TODO MRO? get_own_instance_member, get_instance_member - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } Type::Union(union) => union .elements(db) @@ -269,13 +271,13 @@ impl<'db> Type<'db> { Type::Intersection(_) => { // TODO perform the get_member on each type in the intersection // TODO return the intersection of those results - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } Type::IntLiteral(_) => { // TODO raise error - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } - Type::BooleanLiteral(_) => Type::Unknown, + Type::BooleanLiteral(_) => Type::Unknown(UnknownTypeKind::RedKnotLimitation), } } @@ -283,9 +285,52 @@ impl<'db> Type<'db> { pub fn instance(&self) -> Type<'db> { match self { Type::Any => Type::Any, - Type::Unknown => Type::Unknown, + Type::Unknown(kind) => Type::Unknown(*kind), Type::Class(class) => Type::Instance(*class), - _ => Type::Unknown, // TODO type errors + _ => Type::Unknown(UnknownTypeKind::RedKnotLimitation), // TODO type errors + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum UnknownTypeKind { + /// Temporary variant that indicates that we *should* + /// be able to infer a type here in due course, but currently can't + RedKnotLimitation, + + /// Invalid syntax in the node means we can't infer a type here + InvalidSyntax, + + /// An `Unknown` type stemming from some kind of type error. + /// + /// Examples: + /// - A function was called with argument(s) of incorrect type(s), leading + /// to a diagnostic being emitted and the expression being evaluated as `Unknown`. + /// - An expression was deemed to take place between two invalid types, e.g. `1 + "foo"`. + /// (This is really the same as the first example, since expressions ultimately desguar + /// to function calls, e.g. `1 + "foo"` desugars approximately to `type(1).__add__("foo")`.) + /// - An attribute or method was looked up on an instance of a type that doesn't have that + /// attribute or method. + TypeError, + + /// The symbol was unannotated and the true type can't be reasonably inferred + UnannotatedSymbol, + + /// The type of symbols imported by imports that could not be resolved + UnresolvedImport, + + /// A "second-order" Unknown type, that results from an interaction with + /// a "first-order" Unknown type. For example, if the type of `x` is `Unknown`, + /// the type of `x + 1` will also be `Unknown` + SecondOrder, +} + +impl UnknownTypeKind { + pub(crate) fn union(self, other: Self) -> Self { + if self == other { + self + } else { + UnknownTypeKind::SecondOrder } } } @@ -456,9 +501,6 @@ mod tests { ); } - #[ignore = "\ -A spurious second 'Unresolved import' diagnostic message is emitted on `b.py`, \ -despite the symbol existing in the symbol table for `a.py`"] #[test] fn resolved_import_of_symbol_from_unresolved_import() { let mut db = setup_db(); diff --git a/crates/red_knot_python_semantic/src/types/builder.rs b/crates/red_knot_python_semantic/src/types/builder.rs index e08a9d7e2d103f..76c48fbc533404 100644 --- a/crates/red_knot_python_semantic/src/types/builder.rs +++ b/crates/red_knot_python_semantic/src/types/builder.rs @@ -25,11 +25,12 @@ //! * No type in an intersection can be a supertype of any other type in the intersection (just //! eliminate the supertype from the intersection). //! * An intersection containing two non-overlapping types should simplify to [`Type::Never`]. -use crate::types::{IntersectionType, Type, UnionType}; +use crate::types::{IntersectionType, Type, UnionType, UnknownTypeKind}; use crate::{Db, FxOrderSet}; pub(crate) struct UnionBuilder<'db> { elements: FxOrderSet>, + unknown_elements: Option, db: &'db dyn Db, } @@ -38,6 +39,7 @@ impl<'db> UnionBuilder<'db> { Self { db, elements: FxOrderSet::default(), + unknown_elements: None, } } @@ -48,6 +50,12 @@ impl<'db> UnionBuilder<'db> { self.elements.extend(&union.elements(self.db)); } Type::Never => {} + Type::Unknown(kind) => { + self.unknown_elements = Some( + self.unknown_elements + .map_or(kind, |existing| existing.union(kind)), + ); + } _ => { self.elements.insert(ty); } @@ -56,7 +64,9 @@ impl<'db> UnionBuilder<'db> { self } - pub(crate) fn build(self) -> Type<'db> { + pub(crate) fn build(mut self) -> Type<'db> { + self.elements + .extend(self.unknown_elements.map(Type::Unknown)); match self.elements.len() { 0 => Type::Never, 1 => self.elements[0], diff --git a/crates/red_knot_python_semantic/src/types/display.rs b/crates/red_knot_python_semantic/src/types/display.rs index 7de3f9ebf7c88d..48e4c3627613cf 100644 --- a/crates/red_knot_python_semantic/src/types/display.rs +++ b/crates/red_knot_python_semantic/src/types/display.rs @@ -22,7 +22,7 @@ impl Display for DisplayType<'_> { match self.ty { Type::Any => f.write_str("Any"), Type::Never => f.write_str("Never"), - Type::Unknown => f.write_str("Unknown"), + Type::Unknown(_) => f.write_str("Unknown"), Type::Unbound => f.write_str("Unbound"), Type::None => f.write_str("None"), Type::Module(file) => { diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 138bc733721767..dec871ae97f4e1 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -44,7 +44,7 @@ use crate::semantic_index::SemanticIndex; use crate::types::diagnostic::{TypeCheckDiagnostic, TypeCheckDiagnostics}; use crate::types::{ builtins_symbol_ty_by_name, definitions_ty, global_symbol_ty_by_name, ClassType, FunctionType, - Name, Type, UnionBuilder, + Name, Type, UnionBuilder, UnknownTypeKind, }; use crate::Db; @@ -73,7 +73,9 @@ fn infer_definition_types_cycle_recovery<'db>( input: Definition<'db>, ) -> TypeInference<'db> { let mut inference = TypeInference::default(); - inference.definitions.insert(input, Type::Unknown); + inference + .definitions + .insert(input, Type::Unknown(UnknownTypeKind::RedKnotLimitation)); inference } @@ -517,7 +519,10 @@ impl<'db> TypeInferenceBuilder<'db> { definition: Definition<'db>, ) { // TODO(dhruvmanila): Infer types from annotation or default expression - self.types.definitions.insert(definition, Type::Unknown); + self.types.definitions.insert( + definition, + Type::Unknown(UnknownTypeKind::RedKnotLimitation), + ); } fn infer_parameter_definition( @@ -527,7 +532,10 @@ impl<'db> TypeInferenceBuilder<'db> { ) { // TODO(dhruvmanila): Annotation expression is resolved at the enclosing scope, infer the // parameter type from there - self.types.definitions.insert(definition, Type::Unknown); + self.types.definitions.insert( + definition, + Type::Unknown(UnknownTypeKind::RedKnotLimitation), + ); } fn infer_class_definition_statement(&mut self, class: &ast::StmtClassDef) { @@ -805,7 +813,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_expression(target); // TODO(dhruvmanila): Resolve the target type using the value type and the operator - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_type_alias_statement(&mut self, type_alias_statement: &ast::StmtTypeAlias) { @@ -866,26 +874,21 @@ impl<'db> TypeInferenceBuilder<'db> { asname: _, } = alias; - let module_ty = ModuleName::new(name) - .ok_or(ModuleResolutionError::InvalidSyntax) - .and_then(|module_name| self.module_ty_from_name(module_name)); - - let module_ty = match module_ty { - Ok(ty) => ty, - Err(ModuleResolutionError::InvalidSyntax) => { - tracing::debug!("Failed to resolve import due to invalid syntax"); - Type::Unknown - } - Err(ModuleResolutionError::UnresolvedModule) => { - self.add_diagnostic( - AnyNodeRef::Alias(alias), - "unresolved-import", - format_args!("Import '{name}' could not be resolved."), - ); - Type::Unknown - } + let module_ty = if let Some(module_name) = ModuleName::new(name) { + self.module_ty_from_name(module_name) + } else { + tracing::debug!("Failed to resolve import due to invalid syntax"); + Type::Unknown(UnknownTypeKind::InvalidSyntax) }; + if matches!(module_ty, Type::Unknown(UnknownTypeKind::UnresolvedImport)) { + self.add_diagnostic( + AnyNodeRef::Alias(alias), + "unresolved-import", + format_args!("Import '{name}' could not be resolved."), + ); + } + self.types.definitions.insert(definition, module_ty); } @@ -937,14 +940,14 @@ impl<'db> TypeInferenceBuilder<'db> { &self, tail: Option<&str>, level: NonZeroU32, - ) -> Result { + ) -> Result { let Some(module) = file_to_module(self.db, self.file) else { tracing::debug!( "Relative module resolution '{}' failed; could not resolve file '{}' to a module", format_import_from_module(level.get(), tail), self.file.path(self.db) ); - return Err(ModuleResolutionError::UnresolvedModule); + return Err(UnknownTypeKind::UnresolvedImport); }; let mut level = level.get(); if module.kind().is_package() { @@ -954,14 +957,14 @@ impl<'db> TypeInferenceBuilder<'db> { for _ in 0..level { module_name = module_name .parent() - .ok_or(ModuleResolutionError::UnresolvedModule)?; + .ok_or(UnknownTypeKind::UnresolvedImport)?; } if let Some(tail) = tail { if let Some(valid_tail) = ModuleName::new(tail) { module_name.extend(&valid_tail); } else { tracing::debug!("Relative module resolution failed: invalid syntax"); - return Err(ModuleResolutionError::InvalidSyntax); + return Err(UnknownTypeKind::InvalidSyntax); } } Ok(module_name) @@ -999,12 +1002,17 @@ impl<'db> TypeInferenceBuilder<'db> { alias.name, format_import_from_module(*level, module), ); - module - .and_then(ModuleName::new) - .ok_or(ModuleResolutionError::InvalidSyntax) + if let Some(module_name) = module.and_then(ModuleName::new) { + Ok(module_name) + } else { + tracing::debug!("Module resolution failed: invalid syntax"); + Err(UnknownTypeKind::InvalidSyntax) + } }; - let module_ty = module_name.and_then(|module_name| self.module_ty_from_name(module_name)); + let module_ty = module_name + .map(|module_name| self.module_ty_from_name(module_name)) + .unwrap_or_else(Type::Unknown); let ast::Alias { range: _, @@ -1018,11 +1026,14 @@ impl<'db> TypeInferenceBuilder<'db> { // as would be the case for a symbol with type `Unbound`), so it's appropriate to // think of the type of the imported symbol as `Unknown` rather than `Unbound` let member_ty = module_ty - .unwrap_or(Type::Unbound) .member(self.db, &Name::new(&name.id)) - .replace_unbound_with(self.db, Type::Unknown); + .recursive_transform(self.db, |ty| match ty { + Type::Unbound => Type::Unknown(UnknownTypeKind::UnresolvedImport), + Type::Unknown(_) => Type::Unknown(UnknownTypeKind::SecondOrder), + ty => ty, + }); - if matches!(module_ty, Err(ModuleResolutionError::UnresolvedModule)) { + if matches!(module_ty, Type::Unknown(UnknownTypeKind::UnresolvedImport)) { self.add_diagnostic( AnyNodeRef::StmtImportFrom(import_from), "unresolved-import", @@ -1032,7 +1043,7 @@ impl<'db> TypeInferenceBuilder<'db> { module.unwrap_or_default() ), ); - } else if module_ty.is_ok() && member_ty.is_unknown() { + } else if matches!(member_ty, Type::Unknown(UnknownTypeKind::UnresolvedImport)) { self.add_diagnostic( AnyNodeRef::Alias(alias), "unresolved-import", @@ -1058,13 +1069,10 @@ impl<'db> TypeInferenceBuilder<'db> { } } - fn module_ty_from_name( - &self, - module_name: ModuleName, - ) -> Result, ModuleResolutionError> { + fn module_ty_from_name(&self, module_name: ModuleName) -> Type<'db> { resolve_module(self.db, module_name) .map(|module| Type::Module(module.file())) - .ok_or(ModuleResolutionError::UnresolvedModule) + .unwrap_or(Type::Unknown(UnknownTypeKind::UnresolvedImport)) } fn infer_decorator(&mut self, decorator: &ast::Decorator) -> Type<'db> { @@ -1170,13 +1178,13 @@ impl<'db> TypeInferenceBuilder<'db> { #[allow(clippy::unused_self)] fn infer_string_literal_expression(&mut self, _literal: &ast::ExprStringLiteral) -> Type<'db> { // TODO Literal["..."] or str - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } #[allow(clippy::unused_self)] fn infer_bytes_literal_expression(&mut self, _literal: &ast::ExprBytesLiteral) -> Type<'db> { // TODO - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_fstring_expression(&mut self, fstring: &ast::ExprFString) -> Type<'db> { @@ -1201,7 +1209,7 @@ impl<'db> TypeInferenceBuilder<'db> { } // TODO str type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_fstring_element(&mut self, element: &ast::FStringElement) { @@ -1234,7 +1242,7 @@ impl<'db> TypeInferenceBuilder<'db> { _literal: &ast::ExprEllipsisLiteral, ) -> Type<'db> { // TODO Ellipsis - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_tuple_expression(&mut self, tuple: &ast::ExprTuple) -> Type<'db> { @@ -1311,7 +1319,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_first_comprehension_iter(generators); // TODO generator type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_list_comprehension_expression(&mut self, listcomp: &ast::ExprListComp) -> Type<'db> { @@ -1324,7 +1332,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_first_comprehension_iter(generators); // TODO list type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_dict_comprehension_expression(&mut self, dictcomp: &ast::ExprDictComp) -> Type<'db> { @@ -1338,7 +1346,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_first_comprehension_iter(generators); // TODO dict type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_set_comprehension_expression(&mut self, setcomp: &ast::ExprSetComp) -> Type<'db> { @@ -1351,7 +1359,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_first_comprehension_iter(generators); // TODO set type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_generator_expression_scope(&mut self, generator: &ast::ExprGenerator) { @@ -1507,7 +1515,7 @@ impl<'db> TypeInferenceBuilder<'db> { } // TODO function type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_call_expression(&mut self, call_expression: &ast::ExprCall) -> Type<'db> { @@ -1521,7 +1529,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_expression(func); // TODO resolve to return type of `func`, if its a callable type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_starred_expression(&mut self, starred: &ast::ExprStarred) -> Type<'db> { @@ -1534,7 +1542,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_expression(value); // TODO - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_yield_expression(&mut self, yield_expression: &ast::ExprYield) -> Type<'db> { @@ -1543,7 +1551,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_optional_expression(value.as_deref()); // TODO awaitable type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_yield_from_expression(&mut self, yield_from: &ast::ExprYieldFrom) -> Type<'db> { @@ -1552,7 +1560,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_expression(value); // TODO get type from awaitable - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_await_expression(&mut self, await_expression: &ast::ExprAwait) -> Type<'db> { @@ -1561,7 +1569,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_expression(value); // TODO awaitable type - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_name_expression(&mut self, name: &ast::ExprName) -> Type<'db> { @@ -1589,10 +1597,10 @@ impl<'db> TypeInferenceBuilder<'db> { if unbound_ty.may_be_unbound(self.db) && Some(self.scope) != builtins_scope(self.db) { - Some(unbound_ty.replace_unbound_with( - self.db, - builtins_symbol_ty_by_name(self.db, id), - )) + Some(unbound_ty.recursive_transform(self.db, |ty| match ty { + Type::Unbound => builtins_symbol_ty_by_name(self.db, id), + ty => ty, + })) } else { Some(unbound_ty) } @@ -1606,7 +1614,7 @@ impl<'db> TypeInferenceBuilder<'db> { definitions_ty(self.db, use_def.use_definitions(use_id), unbound_ty) } ExprContext::Store | ExprContext::Del => Type::None, - ExprContext::Invalid => Type::Unknown, + ExprContext::Invalid => Type::Unknown(UnknownTypeKind::InvalidSyntax), } } @@ -1624,7 +1632,7 @@ impl<'db> TypeInferenceBuilder<'db> { match ctx { ExprContext::Load => member_ty, ExprContext::Store | ExprContext::Del => Type::None, - ExprContext::Invalid => Type::Unknown, + ExprContext::Invalid => Type::Unknown(UnknownTypeKind::InvalidSyntax), } } @@ -1638,7 +1646,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_expression(operand); // TODO unary op types - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_binary_expression(&mut self, binary: &ast::ExprBinOp) -> Type<'db> { @@ -1654,7 +1662,7 @@ impl<'db> TypeInferenceBuilder<'db> { match left_ty { Type::Any => Type::Any, - Type::Unknown => Type::Unknown, + Type::Unknown(_) => Type::Unknown(UnknownTypeKind::SecondOrder), Type::IntLiteral(n) => { match right_ty { Type::IntLiteral(m) => { @@ -1683,14 +1691,14 @@ impl<'db> TypeInferenceBuilder<'db> { .checked_rem(m) .map(Type::IntLiteral) // TODO division by zero error - .unwrap_or(Type::Unknown), - _ => Type::Unknown, // TODO + .unwrap_or(Type::Unknown(UnknownTypeKind::RedKnotLimitation)), + _ => Type::Unknown(UnknownTypeKind::RedKnotLimitation), // TODO } } - _ => Type::Unknown, // TODO + _ => Type::Unknown(UnknownTypeKind::RedKnotLimitation), // TODO } } - _ => Type::Unknown, // TODO + _ => Type::Unknown(UnknownTypeKind::RedKnotLimitation), // TODO } } @@ -1706,7 +1714,7 @@ impl<'db> TypeInferenceBuilder<'db> { } // TODO resolve bool op - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_compare_expression(&mut self, compare: &ast::ExprCompare) -> Type<'db> { @@ -1722,7 +1730,7 @@ impl<'db> TypeInferenceBuilder<'db> { for right in comparators.as_ref() { self.infer_expression(right); } - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_subscript_expression(&mut self, subscript: &ast::ExprSubscript) -> Type<'db> { @@ -1737,7 +1745,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_expression(value); // TODO actual subscript support - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_slice_expression(&mut self, slice: &ast::ExprSlice) -> Type<'db> { @@ -1753,7 +1761,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_optional_expression(step.as_deref()); // TODO slice - Type::Unknown + Type::Unknown(UnknownTypeKind::RedKnotLimitation) } fn infer_type_parameters(&mut self, type_parameters: &ast::TypeParams) { @@ -1830,12 +1838,6 @@ fn format_import_from_module(level: u32, module: Option<&str>) -> String { ) } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum ModuleResolutionError { - InvalidSyntax, - UnresolvedModule, -} - #[cfg(test)] mod tests { use anyhow::Context; diff --git a/crates/ruff_benchmark/benches/red_knot.rs b/crates/ruff_benchmark/benches/red_knot.rs index d920793337b077..158afc013c576c 100644 --- a/crates/ruff_benchmark/benches/red_knot.rs +++ b/crates/ruff_benchmark/benches/red_knot.rs @@ -19,18 +19,9 @@ struct Case { const TOMLLIB_312_URL: &str = "https://raw.githubusercontent.com/python/cpython/8e8a4baf652f6e1cee7acde9d78c4b6154539748/Lib/tomllib"; -// This first "unresolved import" is because we don't understand `*` imports yet. -// The following "unresolved import" violations are because we can't distinguish currently from -// "Symbol exists in the module but its type is unknown" and -// "Symbol does not exist in the module" +// The "unresolved import" is because we don't understand `*` imports yet. static EXPECTED_DIAGNOSTICS: &[&str] = &[ "/src/tomllib/_parser.py:7:29: Could not resolve import of 'Iterable' from 'collections.abc'", - "/src/tomllib/_parser.py:10:20: Could not resolve import of 'Any' from 'typing'", - "/src/tomllib/_parser.py:13:5: Could not resolve import of 'RE_DATETIME' from '._re'", - "/src/tomllib/_parser.py:14:5: Could not resolve import of 'RE_LOCALTIME' from '._re'", - "/src/tomllib/_parser.py:15:5: Could not resolve import of 'RE_NUMBER' from '._re'", - "/src/tomllib/_parser.py:20:21: Could not resolve import of 'Key' from '._types'", - "/src/tomllib/_parser.py:20:26: Could not resolve import of 'ParseFloat' from '._types'", "Line 69 is too long (89 characters)", "Use double quotes for strings", "Use double quotes for strings",