Skip to content
Open
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
21 changes: 13 additions & 8 deletions src/sema/check/alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ impl<'p, 's> Checker<'p, 's> {
) -> TypeId {
let is_enum =
alias.is_some_and(|(alias, _)| self.files().flags(alias).intersects(SymFlags::ENUM));
let is_non_generic_top_level =
alias.is_some_and(|(alias, _)| self.is_non_generic_top_level_alias(alias));
// `!isNonGenericTopLevelType`
let has_other_instantiation = alias.is_some_and(|(alias, type_arguments)| {
type_arguments.is_empty()
&& self
.types()
.has_constituent_with_other_instantiation(key, origin)
&& !self.is_non_generic_top_level_alias(alias)
});
let has_other_instantiation = !is_non_generic_top_level
&& alias.is_some_and(|(_, type_arguments)| {
type_arguments.is_empty()
&& self
.types()
.has_constituent_with_other_instantiation(key, origin)
});
self.types().intern_key_with(
key,
&ProvenanceKey {
Expand All @@ -58,6 +60,7 @@ impl<'p, 's> Checker<'p, 's> {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation,
is_non_generic_top_level,
},
)
}
Expand Down Expand Up @@ -101,7 +104,8 @@ impl<'p, 's> Checker<'p, 's> {
return self.with_alias(created, alias, type_arguments);
}
let origin = [created];
let could_contain_type_variables = !self.is_non_generic_top_level_alias(alias)
let is_non_generic_top_level = self.is_non_generic_top_level_alias(alias);
let could_contain_type_variables = !is_non_generic_top_level
&& (self.parts(created).iter()).any(|&t| self.could_contain_type_variables(t));
let provenance = ProvenanceKey {
alias: Some((alias, type_arguments)),
Expand All @@ -111,6 +115,7 @@ impl<'p, 's> Checker<'p, 's> {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation: could_contain_type_variables,
is_non_generic_top_level,
};
(self.types()).intern_key_with(TypeKey::Data(self.data(created)), &provenance)
}
Expand Down
2 changes: 1 addition & 1 deletion src/sema/check/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1777,7 +1777,7 @@ impl<'p, 's> Checker<'p, 's> {
pairs.push((param, second));
}
context.outer_return_context = Some(clone);
let mapper = c.types().mapper(pairs);
let mapper = c.function_mapper(ty, pairs);
Comment thread
robobun marked this conversation as resolved.
Resolved
c.instantiate(ty, mapper)
})
.unwrap_or(ty)
Expand Down
1 change: 1 addition & 0 deletions src/sema/check/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ impl<'p, 's> Checker<'p, 's> {
is_array_literal: false,
is_array_pattern: true,
has_other_instantiation: false,
is_non_generic_top_level: false,
},
))
}
Expand Down
1 change: 1 addition & 0 deletions src/sema/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3528,6 +3528,7 @@ impl<'p, 's> Checker<'p, 's> {
is_array_literal: true,
is_array_pattern: false,
has_other_instantiation: false,
is_non_generic_top_level: false,
},
)
}
Expand Down
26 changes: 4 additions & 22 deletions src/sema/check/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3155,7 +3155,7 @@ impl<'p, 's> Checker<'p, 's> {
compare: &mut dyn FnMut(&mut Self, TypeId, TypeId) -> bool,
) -> MapperId {
if !self.has_type_variables(ty) {
return self.mapper_of_context_not_mentioned_in(ty);
return self.mapper_of_no_type_parameters(ty);
}
let mut pairs = Vec::new();
let mentioned = self.params_mentioned_in(ty, &n.params);
Expand All @@ -3165,28 +3165,13 @@ impl<'p, 's> Checker<'p, 's> {
pairs.push((n.params[i], inferred));
}
}
if pairs.is_empty() {
return self.mapper_of_context_not_mentioned_in(ty);
}
self.types().mapper(pairs)
}

/// Returns an inference context's mapper for a `ty` that mentions none of its type parameters.
/// It isn't nil, so `instantiateType` replaces what has `ObjectFlags::HAS_OTHER_INSTANTIATION`.
/// Only type parameters are looked up in a mapper, so the pair maps nothing.
fn mapper_of_context_not_mentioned_in(&self, ty: TypeId) -> MapperId {
let flags = self.types().object_flags(ty);
if flags.contains(ObjectFlags::HAS_OTHER_INSTANTIATION) {
self.types().mapper_of(&[(TypeId::NEVER, TypeId::UNKNOWN)])
} else {
MapperId::IDENTITY
}
self.function_mapper(ty, pairs)
}

/// `context.mapper`, for what `ty` mentions (`InferenceTypeMapper.Map`).
pub(super) fn fixing_mapper(&mut self, n: &mut Inference, ty: TypeId) -> MapperId {
if !self.may_mention_type_parameter(ty) {
return self.mapper_of_context_not_mentioned_in(ty);
return self.mapper_of_no_type_parameters(ty);
}
let mentioned = self.params_mentioned_in(ty, &n.params);
let mut pairs = Vec::new();
Expand All @@ -3201,10 +3186,7 @@ impl<'p, 's> Checker<'p, 's> {
}
pairs.push((n.params[i], self.get_inferred_type(n, i, true)));
}
if pairs.is_empty() {
return self.mapper_of_context_not_mentioned_in(ty);
}
self.types().mapper(pairs)
self.function_mapper(ty, pairs)
}

/// `inferFromIntraExpressionSites`
Expand Down
25 changes: 24 additions & 1 deletion src/sema/check/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,10 +541,33 @@ impl<'p, 's> Checker<'p, 's> {
false
});
pairs.retain(|pair| pair.0 != pair.1 && !own.contains(&pair.0));
let mapper = self.types().mapper(pairs);
let mapper = self.function_mapper(t, pairs);
(self.instantiate(t, mapper), mapper)
}

/// A mapper that tsgo has as a function, for `ty`: `pairs` is what it maps among the type
/// parameters `ty` mentions. It's never nil, so `instantiateType` walks `ty` even if `pairs` is
/// empty.
pub(super) fn function_mapper(&self, ty: TypeId, pairs: Vec<(TypeId, TypeId)>) -> MapperId {
Comment thread
robobun marked this conversation as resolved.
Resolved
match pairs.is_empty() {
true => self.mapper_of_no_type_parameters(ty),
false => self.types().mapper(pairs),
}
}

/// `function_mapper` with no pairs. The walk replaces what has
/// `ObjectFlags::HAS_OTHER_INSTANTIATION`, and nothing else, so a `ty` without it is returned
/// unchanged through the identity mapper. Only type parameters are looked up in a mapper, so
/// the pair maps nothing.
pub(super) fn mapper_of_no_type_parameters(&self, ty: TypeId) -> MapperId {
let flags = self.types().object_flags(ty);
if flags.contains(ObjectFlags::HAS_OTHER_INSTANTIATION) {
self.types().mapper_of(&[(TypeId::NEVER, TypeId::UNKNOWN)])
} else {
MapperId::IDENTITY
}
}

/// `getRestrictiveInstantiation`, with `getRestrictiveTypeParameter`. Restrictive type
/// parameters map to themselves, so the restrictive instantiation of a restrictive instantiation is itself.
pub(super) fn restrictive_instantiation(&mut self, t: TypeId) -> TypeId {
Expand Down
3 changes: 3 additions & 0 deletions src/sema/check/mapped.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2315,6 +2315,7 @@ impl<'p, 's> Checker<'p, 's> {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation: false,
is_non_generic_top_level: false,
},
);
}
Expand Down Expand Up @@ -2383,6 +2384,7 @@ impl<'p, 's> Checker<'p, 's> {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation: false,
is_non_generic_top_level: false,
},
)
}
Expand Down Expand Up @@ -2461,6 +2463,7 @@ impl<'p, 's> Checker<'p, 's> {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation: false,
is_non_generic_top_level: false,
},
)
};
Expand Down
2 changes: 2 additions & 0 deletions src/sema/check/task_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ fn borrowed_key_finds_type_interned_with_owned_lists() {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation: false,
is_non_generic_top_level: false,
};
let id = types.intern_key_with(TypeKey::Union(&members), &borrowed);
let owned = Provenance {
Expand All @@ -433,6 +434,7 @@ fn borrowed_key_finds_type_interned_with_owned_lists() {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation: false,
is_non_generic_top_level: false,
};
let union = TypeData::Union(ShortList::copy_from_slice_in(&members, arena));
assert_eq!(types.intern_with(union, owned), id);
Expand Down
2 changes: 2 additions & 0 deletions src/sema/check/unions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,7 @@ impl<'p, 's> Checker<'p, 's> {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation: false,
is_non_generic_top_level: false,
},
)
}
Expand Down Expand Up @@ -1248,6 +1249,7 @@ impl<'p, 's> Checker<'p, 's> {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation: false,
is_non_generic_top_level: false,
},
)
})
Expand Down
20 changes: 18 additions & 2 deletions src/sema/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1384,6 +1384,10 @@ pub struct Provenance<'s> {
/// `ObjectFlags::HAS_OTHER_INSTANTIATION`, if `alias` has no type arguments and isn't declared at
/// the top level of a file (`isNonGenericTopLevelType`).
pub has_other_instantiation: bool,
/// `isNonGenericTopLevelType`: `alias` has no type parameters and is declared at the top level
/// of a file. `couldContainTypeVariables` is false for such a union or intersection, whatever
/// its members, so `instantiateType` returns it unchanged.
pub is_non_generic_top_level: bool,
}

/// `getTypeInstantiationKey`, for `ObjectType.instantiations` of a mapped type.
Expand Down Expand Up @@ -1613,6 +1617,7 @@ pub struct ProvenanceKey<'a> {
pub is_array_literal: bool,
pub is_array_pattern: bool,
pub has_other_instantiation: bool,
pub is_non_generic_top_level: bool,
}

impl ProvenanceKey<'_> {
Expand All @@ -1624,6 +1629,7 @@ impl ProvenanceKey<'_> {
&& !self.is_array_literal
&& !self.is_array_pattern
&& !self.has_other_instantiation
&& !self.is_non_generic_top_level
}

fn is(self, provenance: &Provenance) -> bool {
Expand All @@ -1648,6 +1654,7 @@ impl ProvenanceKey<'_> {
&& self.is_array_literal == provenance.is_array_literal
&& self.is_array_pattern == provenance.is_array_pattern
&& self.has_other_instantiation == provenance.has_other_instantiation
&& self.is_non_generic_top_level == provenance.is_non_generic_top_level
}

/// Same result as `Follow::is_bound` on the `Provenance` for this key.
Expand Down Expand Up @@ -1691,6 +1698,7 @@ impl ProvenanceKey<'_> {
is_array_literal: self.is_array_literal,
is_array_pattern: self.is_array_pattern,
has_other_instantiation: self.has_other_instantiation,
is_non_generic_top_level: self.is_non_generic_top_level,
}
}
}
Expand Down Expand Up @@ -3748,6 +3756,9 @@ impl<'p, 's> Types<'p, 's> {
if provenance.has_other_instantiation {
flags |= ObjectFlags::HAS_OTHER_INSTANTIATION;
}
if is_union_or_intersection && provenance.is_non_generic_top_level {
flags.remove(ObjectFlags::COULD_CONTAIN_TYPE_VARIABLES);
}
if provenance.alias.is_some() && matches!(data, TypeData::Cond { .. }) {
flags |= ObjectFlags::HAS_OTHER_INSTANTIATION;
}
Expand Down Expand Up @@ -4684,7 +4695,8 @@ follow_struct!(Provenance<'_> {
stored_under,
is_array_literal,
is_array_pattern,
has_other_instantiation
has_other_instantiation,
is_non_generic_top_level
});
follow_struct!(InstantiationKey {
type_arguments,
Expand Down Expand Up @@ -4952,7 +4964,8 @@ clone_in_struct!(Provenance {
stored_under,
is_array_literal,
is_array_pattern,
has_other_instantiation
has_other_instantiation,
is_non_generic_top_level
});
clone_in_enum!(UnionOrigin {
None,
Expand Down Expand Up @@ -5143,6 +5156,7 @@ fn visit_type_as_content<V: Hashing>(created: &OwnedTypeKey, content: &mut V) {
is_array_literal,
is_array_pattern,
has_other_instantiation,
is_non_generic_top_level,
} = &**provenance;
alias.visit(content);
match origin {
Expand All @@ -5157,6 +5171,7 @@ fn visit_type_as_content<V: Hashing>(created: &OwnedTypeKey, content: &mut V) {
is_array_literal.visit(content);
is_array_pattern.visit(content);
has_other_instantiation.visit(content);
is_non_generic_top_level.visit(content);
}
}

Expand Down Expand Up @@ -5464,6 +5479,7 @@ mod tests {
is_array_literal: false,
is_array_pattern: false,
has_other_instantiation: false,
is_non_generic_top_level: false,
};
let under = InstantiationKey {
type_arguments: MapperId::IDENTITY,
Expand Down
Loading
Loading