1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
use crate::semantics::*; use crate::syntax::*; use crate::BitSize; use crate::*; use fraction::ToPrimitive; pub struct ImpreciseFloatLiteral; impl ImpreciseFloatLiteral { fn check_literal( literal: Node, type_: Type, class: Id, analysis: &mut Analysis, diagnostics: &mut Vec<Diagnostic>, ) -> Option<()> { let class = analysis.navigator.find_node(class)?; let (name, _, _) = analysis.navigator.qualified_name_of(&class)?; match (literal.kind, name.as_str()) { (FloatExpression(_, fraction), "Loa/Float32") => { Self::assert_fraction_precision( literal.span, type_, fraction, BitSize::Size32, diagnostics, ); } (FloatExpression(_, fraction), "Loa/Float64") => { Self::assert_fraction_precision( literal.span, type_, fraction, BitSize::Size64, diagnostics, ); } _ => {} } None } fn assert_fraction_precision( span: Span, type_: Type, fraction: BigFraction, size: BitSize, diagnostics: &mut Vec<Diagnostic>, ) { let big_formatted = format!("{:.1$}", fraction, 310); let cast_formatted = match size { BitSize::Size32 => fraction.to_f32().unwrap().to_string(), BitSize::Size64 => fraction.to_f64().unwrap().to_string(), _ => return, }; if big_formatted != cast_formatted { diagnostics.push(Diagnostic::TooPreciseFloat(span, type_, fraction)) } } } impl Checker for ImpreciseFloatLiteral { fn check(&self, analysis: &mut Analysis, diagnostics: &mut Vec<Diagnostic>) { for literal in analysis.navigator.all_number_literals() { let type_ = analysis.types.get_type_of_expression(&literal); match type_ { Type::UnresolvedInteger(_, _) => continue, Type::UnresolvedFloat(_, _) => continue, Type::Class(_, class, _) => { Self::check_literal(literal, type_, class, analysis, diagnostics); continue; } _ => {} } diagnostics.push(Diagnostic::InvalidLiteralType(literal.span, type_)); } } }