diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index d0a6decd..c222cba6 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "ghul.compiler": { - "version": "0.8.43", + "version": "0.8.44", "commands": [ "ghul-compiler" ] diff --git a/Directory.Build.props b/Directory.Build.props index 19f5d443..f53821a6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 0.8.44-alpha.80 + 0.8.45-alpha.5 $(NoWarn);NU1507 diff --git a/integration-tests/semantic/generic-function-argument-type-inference-1/err.expected b/integration-tests/semantic/generic-function-argument-type-inference-1/err.expected index 1a91ec86..bb7842cd 100644 --- a/integration-tests/semantic/generic-function-argument-type-inference-1/err.expected +++ b/integration-tests/semantic/generic-function-argument-type-inference-1/err.expected @@ -1,4 +1,4 @@ -test.ghul: 14,18..14,24: error: no static overload found for function(Ghul.int, Ghul.single), tried Test.GenericFunctionTypeInference.function[T](a: T, b: T) -> T -test.ghul: 24,18..24,40: error: no static overload found for function(Ghul.int[], Ghul.object[]), tried Test.GenericFunctionTypeInference.function[T](a: T, b: T) -> T -test.ghul: 27,18..27,58: error: no static overload found for function(Ghul.int[], Collections.LIST[Ghul.int]), tried Test.GenericFunctionTypeInference.function[T](a: T, b: T) -> T -test.ghul: 28,18..28,40: error: no static overload found for function(Ghul.int[], Ghul.Pipes.Pipe[Ghul.int]), tried Test.GenericFunctionTypeInference.function[T](a: T, b: T) -> T +test.ghul: 13,14..13,20: error: no static overload found for function(Ghul.int, Ghul.single), tried function[T](a: T, b: T) -> T +test.ghul: 24,14..24,36: error: no static overload found for function(Ghul.int[], System.ISpanFormattable[]), tried function[T](a: T, b: T) -> T +test.ghul: 27,14..27,54: error: no static overload found for function(Ghul.int[], Collections.LIST[Ghul.int]), tried function[T](a: T, b: T) -> T +test.ghul: 28,14..28,36: error: no static overload found for function(Ghul.int[], Ghul.Pipes.Pipe[Ghul.int]), tried function[T](a: T, b: T) -> T diff --git a/integration-tests/semantic/generic-function-argument-type-inference-1/test.ghul b/integration-tests/semantic/generic-function-argument-type-inference-1/test.ghul index e3701a63..3a9886f8 100644 --- a/integration-tests/semantic/generic-function-argument-type-inference-1/test.ghul +++ b/integration-tests/semantic/generic-function-argument-type-inference-1/test.ghul @@ -1,34 +1,33 @@ -namespace Test.GenericFunctionTypeInference is - use Collections; +use Collections; - entry() is - function(1, 2); - - function(1.0, 2.0); +entry() is + function(1, 2); + + function(1.0, 2.0); - function("a", "b"); + function("a", "b"); - function(true, false); + function(true, false); - // expect an error - function(1, 2.0); + // expect an error + function(1, 2.0); - function([1234], [5678]); + function([1234], [5678]); - function([1, 2.0], [3, 4.0]); + function([1, 2.0], [3, 4.0]); - function([1, 2.0, "a"], [3, 4.0, "b"]); + function([1, 2.0, "a"], [3, 4.0, "b"]); - // expect an error - function([1, 2, 3], [4, 5, 6.0]); + // expect error + // infers a not very useful interface - LUB needs tuning + function([1, 2, 3], [4, 5, 6.0]); - // expect errors. Note these don't work in C# either: - function([1234, 5678], LIST[int]([91011, 121314])); - function([1, 2, 3], [4, 5, 6] |); - si + // expect errors. Note these don't work in C# either: + function([1234, 5678], LIST[int]([91011, 121314])); + function([1, 2, 3], [4, 5, 6] |); +si - function[T](a: T, b: T) -> T is - return a; - si +function[T](a: T, b: T) -> T is + return a; si diff --git a/src/semantic/dotnet/symbol_factory.ghul b/src/semantic/dotnet/symbol_factory.ghul index eb35fb12..b1c4402e 100644 --- a/src/semantic/dotnet/symbol_factory.ghul +++ b/src/semantic/dotnet/symbol_factory.ghul @@ -227,7 +227,7 @@ namespace Semantic.DotNet is fi return t.get_generic_parameter_constraints().count == 0; - si + si add_members(result: Symbols.Scoped, type: TYPE) is let properties = MAP[System.Reflection.MethodInfo,PROPERTY_DETAILS](); diff --git a/src/semantic/types/tuple.ghul b/src/semantic/types/tuple.ghul index c87399b9..1c817c8b 100644 --- a/src/semantic/types/tuple.ghul +++ b/src/semantic/types/tuple.ghul @@ -14,8 +14,6 @@ namespace Semantic.Types is assert args? else "tuple args are null"; assert args | .all(a => a?) else "tuple at least one null argument"; - assert !names? \/ names | .all(n => n?) else "tuple at least one null name"; - return if !args? then "()"; @@ -27,7 +25,7 @@ namespace Semantic.Types is si _get_element_name(names: Collections.List[string], index: int) -> string static => - if names? /\ index < names.count then + if names? /\ index < names.count /\ names[index]? then "{names[index]}: " else "" @@ -41,8 +39,6 @@ namespace Semantic.Types is ) is super.init(Symbols.TUPLE(location, symbol, arguments, names)); - assert !names? \/ names | .all(n => n?) else "tuple at least one null name"; - self.names = names; si diff --git a/src/semantic/types/type.ghul b/src/semantic/types/type.ghul index 7a15857d..956d3a87 100644 --- a/src/semantic/types/type.ghul +++ b/src/semantic/types/type.ghul @@ -73,6 +73,7 @@ namespace Semantic.Types is is_function_with_any_implicit_argument_types: bool => false; is_ref: bool => false; // specifically 'ref', not just a reference type is_value_tuple: bool => false; + is_unsafe_constraints: bool => symbol.is_unsafe_constraints; init() is si diff --git a/src/syntax/process/compile_expressions.ghul b/src/syntax/process/compile_expressions.ghul index d6a23547..ffff1941 100644 --- a/src/syntax/process/compile_expressions.ghul +++ b/src/syntax/process/compile_expressions.ghul @@ -968,7 +968,7 @@ namespace Syntax.Process is types.add(Semantic.Types.ERROR()); elif Value.check_is_consumable(_logger, v.location, v.value) then - names.add(null); + names.add("`{index}"); if element_type_constraint? then let type = element_type_constraint; diff --git a/src/syntax/process/least_upper_bound_map.ghul b/src/syntax/process/least_upper_bound_map.ghul index b944657f..82c91fc0 100644 --- a/src/syntax/process/least_upper_bound_map.ghul +++ b/src/syntax/process/least_upper_bound_map.ghul @@ -12,6 +12,7 @@ namespace Syntax.Process is si class LEAST_UPPER_BOUND_MAP is + _any_unsafe_constraints: bool; _mode: LUB_MODE; types: LIST[Type]; @@ -28,6 +29,10 @@ namespace Syntax.Process is add(type: Type) is types.add(type); + if type.is_unsafe_constraints then + _any_unsafe_constraints = true; + fi + _update_element_names_from(type); si @@ -71,20 +76,33 @@ namespace Syntax.Process is // case it will return object, which may still be better // than a fairly random choice of interface type let best_concrete_type = _try_get_best_concrete(); - if best_concrete_type? then - return best_concrete_type; - fi // this is LUB applied to all elements and all traits // they implement. It has a tendency to select unhelpful // traits, and needs tuning somehow to prioritize // traits that are relevant based on context let best_trait_type = _try_get_best_trait(); - if best_trait_type? then - return best_trait_type; - fi - return null; + // this still might not be enough - we might need to record the + // average depth difference (='specificity') per type, but that + // could be slow + if best_concrete_type? /\ best_trait_type? then + let total_concrete_depth_difference = + types | .reduce(0, (d, t) => d + (t.depth - best_concrete_type.depth)); + + let total_trait_depth_difference = + types | .reduce(0, (d, t) => d + (t.depth - best_trait_type.depth)); + + if total_trait_depth_difference < total_concrete_depth_difference then + return best_trait_type + else + return best_concrete_type + fi + elif best_concrete_type? then + return best_concrete_type + else + return best_trait_type + fi si _try_get_best_assignable() -> Type is @@ -149,6 +167,12 @@ namespace Syntax.Process is for list in result.values do for type in list do + if !_any_unsafe_constraints /\ type.is_unsafe_constraints then + // only allow unsafe constraints if some of the element + // types have unsafe constraints: + continue; + fi + if !best? then best = type; is_ambiguous = false;