use crate::checker::EnvResolve;
use crate::store::Store;
use syntax::ast::{Expression, Span};
use syntax::types::Type;
use crate::checker::TaskState;
impl TaskState<'_> {
pub(crate) fn check_valid_cast(
&mut self,
store: &Store,
raw_source_ty: &Type,
raw_target_ty: &Type,
span: Span,
) {
let source_ty = raw_source_ty.resolve_in(&self.env);
let target_ty = raw_target_ty.resolve_in(&self.env);
if source_ty.contains_error() || target_ty.contains_error() {
return;
}
if source_ty.is_complex() || target_ty.is_complex() {
self.sink.push(diagnostics::infer::invalid_cast(
raw_source_ty,
raw_target_ty,
span,
));
return;
}
if source_ty.has_underlying_rune() && target_ty.has_underlying_byte() {
self.sink.push(diagnostics::infer::invalid_cast(
raw_source_ty,
raw_target_ty,
span,
));
return;
}
if source_ty.has_underlying_numeric_type() && target_ty.has_underlying_numeric_type() {
return;
}
if source_ty.has_underlying_rune() && target_ty.is_string() {
return;
}
if (source_ty.is_string() && target_ty.has_byte_or_rune_slice_underlying())
|| (target_ty.is_string() && source_ty.has_byte_or_rune_slice_underlying())
{
return;
}
if source_ty.is_byte_slice() && target_ty.is_byte_slice() {
return;
}
let peeled_target = store.peel_alias(&target_ty);
if let Type::Nominal { id, params, .. } = &peeled_target
&& let Some(interface) = store.get_interface(id).cloned()
&& self
.satisfies_interface(store, &source_ty, &interface, id, params, &span)
.is_ok()
{
return;
}
if store.peel_alias_deep(&source_ty) == store.peel_alias_deep(&target_ty) {
return;
}
self.sink.push(diagnostics::infer::invalid_cast(
raw_source_ty,
raw_target_ty,
span,
));
}
pub(crate) fn check_redundant_cast(
&mut self,
raw_source_ty: &Type,
raw_target_ty: &Type,
span: Span,
) -> bool {
let source_ty = raw_source_ty.resolve_in(&self.env);
if source_ty == raw_target_ty.resolve_in(&self.env) {
self.sink
.push(diagnostics::infer::redundant_cast(&source_ty, span));
return true;
}
false
}
pub(crate) fn check_redundant_literal_cast(
&mut self,
expression: &Expression,
target_ty: &Type,
expected_ty: &Type,
span: Span,
) {
let target_resolved = target_ty.resolve_in(&self.env);
let expected_resolved = expected_ty.resolve_in(&self.env);
if expected_resolved.is_variable() {
return;
}
if expected_resolved != target_resolved {
return;
}
let inner_expression = unwrap_parens_and_negation(expression);
match inner_expression {
Expression::Literal {
literal: syntax::ast::Literal::Integer { .. },
..
} if target_resolved.is_numeric() && !target_resolved.is_rune() => {
self.sink
.push(diagnostics::infer::redundant_cast(&target_resolved, span));
}
Expression::Literal {
literal: syntax::ast::Literal::Float { .. },
..
} if target_resolved.is_float() => {
self.sink
.push(diagnostics::infer::redundant_cast(&target_resolved, span));
}
_ => {}
}
}
}
fn unwrap_parens_and_negation(expression: &Expression) -> &Expression {
match expression {
Expression::Paren { expression, .. } => unwrap_parens_and_negation(expression),
Expression::Unary {
operator: syntax::ast::UnaryOperator::Negative,
expression,
..
} => unwrap_parens_and_negation(expression),
_ => expression,
}
}