Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

tell different variants apart in redundant comparison checks

+81 -8
+25
compiler-core/src/ast/typed.rs
··· 912 912 } 913 913 914 914 #[must_use] 915 + /// Returns true if the value is a literal record builder like 916 + /// `Wibble(1, 2)`, `module.Wobble("a")` 917 + /// 915 918 pub fn is_record_builder(&self) -> bool { 916 919 match self { 917 920 TypedExpr::Call { fun, .. } => fun.is_record_builder(), ··· 921 924 .. 922 925 } => true, 923 926 _ => false, 927 + } 928 + } 929 + 930 + /// If the given expression is a literal record builder, this will return 931 + /// index of the variant being built. 932 + /// 933 + pub fn variant_index(&self) -> Option<u16> { 934 + match self { 935 + TypedExpr::Call { fun, .. } => fun.variant_index(), 936 + TypedExpr::Var { 937 + constructor: 938 + ValueConstructor { 939 + variant: ValueConstructorVariant::Record { variant_index, .. }, 940 + .. 941 + }, 942 + .. 943 + } 944 + | TypedExpr::ModuleSelect { 945 + constructor: ModuleValueConstructor::Record { variant_index, .. }, 946 + .. 947 + } => Some(*variant_index), 948 + _ => None, 924 949 } 925 950 } 926 951
+3
compiler-core/src/type_.rs
··· 708 708 field_map, 709 709 location, 710 710 documentation, 711 + variant_index, 711 712 .. 712 713 } => ModuleValueConstructor::Record { 713 714 name: name.clone(), 715 + variant_index: *variant_index, 714 716 field_map: field_map.clone(), 715 717 arity: *arity, 716 718 type_, ··· 850 852 pub enum ModuleValueConstructor { 851 853 Record { 852 854 name: EcoString, 855 + variant_index: u16, 853 856 arity: u16, 854 857 type_: Arc<Type>, 855 858 field_map: Option<FieldMap>,
+29 -8
compiler-core/src/type_/expression.rs
··· 3634 3634 } => { 3635 3635 let constructor = self.infer_value_constructor(&module, &name, &location)?; 3636 3636 3637 - let (tag, field_map) = match &constructor.variant { 3637 + let (tag, field_map, variant_index) = match &constructor.variant { 3638 3638 ValueConstructorVariant::Record { 3639 - name, field_map, .. 3640 - } => (name.clone(), field_map.clone()), 3639 + name, 3640 + field_map, 3641 + variant_index, 3642 + .. 3643 + } => (name.clone(), field_map.clone(), *variant_index), 3641 3644 3642 3645 ValueConstructorVariant::ModuleFn { .. } 3643 3646 | ValueConstructorVariant::LocalVariable { .. } => { ··· 3670 3673 .clone(); 3671 3674 let module_value_constructor = ModuleValueConstructor::Record { 3672 3675 name: name.clone(), 3676 + variant_index, 3673 3677 field_map: field_map.clone(), 3674 3678 arity: args.len() as u16, 3675 3679 type_: Arc::clone(&type_), ··· 5009 5013 args: args_other, 5010 5014 .. 5011 5015 }, 5012 - ) => { 5013 - if fun_one.is_record_builder() && fun_other.is_record_builder() { 5016 + ) => match (fun_one.variant_index(), fun_other.variant_index()) { 5017 + // Both have to be literal record builders, otherwise we can't really tell 5018 + // anything at compile time! 5019 + (None, None) | (None, Some(_)) | (Some(_), None) => StaticComparison::CantTell, 5020 + 5021 + // If they're both literal record builders and are building different 5022 + // variants, then we know they'll always be different. 5023 + (Some(index_one), Some(index_other)) if index_one != index_other => { 5024 + StaticComparison::CertainlyDifferent 5025 + } 5026 + 5027 + // Otherwise we need to check their arguments pairwise: 5028 + (Some(_), Some(_)) => { 5014 5029 let mut comparison = StaticComparison::CertainlyEqual; 5015 5030 for (one, other) in args_one.iter().zip(args_other.iter()) { 5016 5031 match static_compare(&one.value, &other.value) { 5017 5032 StaticComparison::CertainlyEqual => (), 5033 + // If we can tell any of the arguments are never going to 5034 + // be the same then we can short circuit and be sure 5035 + // that the two variants are not the same as well! 5018 5036 StaticComparison::CertainlyDifferent => { 5019 5037 return StaticComparison::CertainlyDifferent; 5020 5038 } 5039 + // If we can't compare two of the arguments then there's 5040 + // nothing we can tell at compile time. Notice how we 5041 + // don't short circuit here: we still want to go over all 5042 + // the other arguments because we might find two that are 5043 + // certainly going to be different! 5021 5044 StaticComparison::CantTell => comparison = StaticComparison::CantTell, 5022 5045 } 5023 5046 } 5024 5047 comparison 5025 - } else { 5026 - StaticComparison::CantTell 5027 5048 } 5028 - } 5049 + }, 5029 5050 5030 5051 ( 5031 5052 TypedExpr::RecordAccess {
+24
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__different_records_2_redundant_comparison.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub type Either {\n Left(Int)\n Right(Int)\n}\n\npub fn main() -> Bool {\n Left(1) == Right(1)\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub type Either { 8 + Left(Int) 9 + Right(Int) 10 + } 11 + 12 + pub fn main() -> Bool { 13 + Left(1) == Right(1) 14 + } 15 + 16 + 17 + ----- WARNING 18 + warning: Redundant comparison 19 + ┌─ /src/warning/wrn.gleam:8:3 20 + 21 + 8 │ Left(1) == Right(1) 22 + │ ^^^^^^^^^^^^^^^^^^^ This is always `False` 23 + 24 + This comparison is redundant since it always fails.