Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -615,8 +615,7 @@ e: list[Any] | None = [1]
reveal_type(e) # revealed: list[Any]

f: list[Any] | None = f2(1)
# TODO: Better constraint solver.
reveal_type(f) # revealed: list[int] | None
reveal_type(f) # revealed: list[Any] | None

g: list[Any] | dict[Any, Any] = f3(1)
# TODO: Better constraint solver.
Expand Down
2 changes: 1 addition & 1 deletion crates/ty_python_semantic/resources/mdtest/promotion.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ x11: list[Literal[1] | Literal[2] | Literal[3]] = [1, 2, 3]
reveal_type(x11) # revealed: list[Literal[1, 2, 3]]

x12: Y[Y[Literal[1]]] = [[1]]
reveal_type(x12) # revealed: list[Y[Literal[1]]]
reveal_type(x12) # revealed: list[list[Literal[1]]]

x13: list[tuple[Literal[1], Literal[2], Literal[3]]] = [(1, 2, 3)]
reveal_type(x13) # revealed: list[tuple[Literal[1], Literal[2], Literal[3]]]
Expand Down
63 changes: 34 additions & 29 deletions crates/ty_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use ruff_diagnostics::{Edit, Fix};
use rustc_hash::FxHashMap;

use std::borrow::Cow;
use std::cell::RefCell;
use std::time::Duration;

use bitflags::bitflags;
Expand Down Expand Up @@ -51,7 +50,7 @@ use crate::types::bound_super::BoundSuperType;
use crate::types::call::{Binding, Bindings, CallArguments, CallableBinding};
pub(crate) use crate::types::callable::{CallableType, CallableTypes};
pub(crate) use crate::types::class_base::ClassBase;
use crate::types::constraints::ConstraintSetBuilder;
use crate::types::constraints::{ConstraintSetBuilder, Solutions};
use crate::types::context::{LintDiagnosticGuard, LintDiagnosticGuardBuilder};
use crate::types::diagnostic::{INVALID_AWAIT, INVALID_TYPE_FORM};
pub use crate::types::display::{DisplaySettings, TypeDetail, TypeDisplayDetails};
Expand All @@ -60,10 +59,10 @@ use crate::types::function::{
DataclassTransformerFlags, DataclassTransformerParams, FunctionDecorators, FunctionSpans,
FunctionType, KnownFunction,
};
pub(crate) use crate::types::generics::GenericContext;
use crate::types::generics::{
ApplySpecialization, InferableTypeVars, Specialization, bind_typevar,
};
pub(crate) use crate::types::generics::{GenericContext, SpecializationBuilder};
use crate::types::infer::InferenceFlags;
use crate::types::known_instance::{InternedConstraintSet, InternedType, UnionTypeInstance};
pub use crate::types::method::{BoundMethodType, KnownBoundMethodType, WrapperDescriptorKind};
Expand Down Expand Up @@ -1902,17 +1901,38 @@ impl<'db> Type<'db> {
let generic_context = specialization.generic_context(db);

// Collect the type mappings used to narrow the type context.
let tcx_mappings = {
let mut builder =
SpecializationBuilder::new(db, generic_context.inferable_typevars(db));

if let Some(tcx) = tcx.annotation {
//
// We use a forward CSA check (`alias_instance ≤ tcx`) to infer what each typevar
// in the identity specialization maps to in the type context. For example, if
// `tcx = list[int]` and `alias_instance = list[T]`, the CSA produces `T = int`.
let tcx_mappings: FxHashMap<_, _> = tcx
.annotation
.and_then(|tcx| {
let alias_instance = Type::instance(db, class_literal.identity_specialization(db));
let _ = builder.infer_reverse(constraints, tcx, alias_instance);
}

builder.into_type_mappings()
};
let set = alias_instance.when_constraint_set_assignable_to(db, tcx, constraints);
match set.solutions(db, constraints) {
Solutions::Constrained(solutions) => {
let mut mappings = FxHashMap::default();
for solution in solutions.iter() {
for binding in solution {
mappings
.entry(binding.bound_typevar.identity(db))
.and_modify(|existing| {
*existing = UnionType::from_two_elements(
db,
*existing,
binding.solution,
);
})
.or_insert(binding.solution);
}
}
Some(mappings)
}
_ => None,
}
})
.unwrap_or_default();

for (type_var, ty) in generic_context.variables(db).zip(specialization.types(db)) {
let variance = type_var.variance_with_polarity(db, polarity);
Expand Down Expand Up @@ -5501,12 +5521,6 @@ impl<'db> Type<'db> {
match type_mapping {
TypeMapping::EagerExpansion => unreachable!("handled above"),

// For UniqueSpecialization, get raw value type, apply specialization, then apply mapping.
TypeMapping::UniqueSpecialization { .. } => {
let value_type = alias.raw_value_type(db);
alias.apply_function_specialization(db, value_type).apply_type_mapping_impl(db, type_mapping, tcx, visitor)
}

_ => {
let value_type = alias.raw_value_type(db).apply_type_mapping_impl(db, type_mapping, tcx, visitor);
alias.apply_function_specialization(db, value_type).apply_type_mapping_impl(db, type_mapping, tcx, visitor)
Expand All @@ -5531,7 +5545,6 @@ impl<'db> Type<'db> {
Type::LiteralValue(_) => match type_mapping {
TypeMapping::ApplySpecialization(_) |
TypeMapping::ApplySpecializationWithMaterialization { .. } |
TypeMapping::UniqueSpecialization { .. } |
TypeMapping::BindLegacyTypevars(_) |
TypeMapping::BindSelf { .. } |
TypeMapping::ReplaceSelf { .. } |
Expand All @@ -5547,7 +5560,6 @@ impl<'db> Type<'db> {
Type::Dynamic(_) => match type_mapping {
TypeMapping::ApplySpecialization(_) |
TypeMapping::ApplySpecializationWithMaterialization { .. } |
TypeMapping::UniqueSpecialization { .. } |
TypeMapping::BindLegacyTypevars(_) |
TypeMapping::BindSelf(..) |
TypeMapping::ReplaceSelf { .. } |
Expand Down Expand Up @@ -6328,11 +6340,6 @@ pub enum TypeMapping<'a, 'db> {
specialization: ApplySpecialization<'a, 'db>,
materialization_kind: MaterializationKind,
},
/// Resets any specializations to contain unique synthetic type variables.
UniqueSpecialization {
// A list of synthetic type variables, and the types they replaced.
specialization: RefCell<Vec<(BoundTypeVarInstance<'db>, Type<'db>)>>,
},
/// Replaces any literal types with their corresponding promoted type form (e.g. `Literal["string"]`
/// to `str`, or `def _() -> int` to `Callable[[], int]`).
Promote(PromotionMode, PromotionKind),
Expand Down Expand Up @@ -6384,8 +6391,7 @@ impl<'db> TypeMapping<'_, 'db> {
}),
)
}
TypeMapping::UniqueSpecialization { .. }
| TypeMapping::Promote(..)
TypeMapping::Promote(..)
| TypeMapping::BindLegacyTypevars(_)
| TypeMapping::Materialize(_)
| TypeMapping::ReplaceParameterDefaults
Expand Down Expand Up @@ -6430,7 +6436,6 @@ impl<'db> TypeMapping<'_, 'db> {
},
TypeMapping::Promote(mode, kind) => TypeMapping::Promote(mode.flip(), *kind),
TypeMapping::ApplySpecialization(_)
| TypeMapping::UniqueSpecialization { .. }
| TypeMapping::BindLegacyTypevars(_)
| TypeMapping::BindSelf(..)
| TypeMapping::ReplaceSelf { .. }
Expand Down
Loading
Loading