mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
parent
fffbbd08b0
commit
b87f09115c
7 changed files with 80 additions and 17 deletions
|
@ -566,6 +566,7 @@ fn can_annotation_help(
|
||||||
region,
|
region,
|
||||||
alias_needs: alias.type_variables.len() as u8,
|
alias_needs: alias.type_variables.len() as u8,
|
||||||
type_got: args.len() as u8,
|
type_got: args.len() as u8,
|
||||||
|
alias_kind: alias.kind,
|
||||||
});
|
});
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,6 +369,7 @@ fn canonicalize_alias<'a>(
|
||||||
typ: symbol,
|
typ: symbol,
|
||||||
variable_region: loc_lowercase.region,
|
variable_region: loc_lowercase.region,
|
||||||
variable_name: loc_lowercase.value.clone(),
|
variable_name: loc_lowercase.value.clone(),
|
||||||
|
alias_kind: AliasKind::Structural,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
AliasKind::Opaque => {
|
AliasKind::Opaque => {
|
||||||
|
@ -2688,6 +2689,7 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
env,
|
env,
|
||||||
&mut alias.typ,
|
&mut alias.typ,
|
||||||
alias_name,
|
alias_name,
|
||||||
|
alias.kind,
|
||||||
alias.region,
|
alias.region,
|
||||||
rest,
|
rest,
|
||||||
can_still_report_error,
|
can_still_report_error,
|
||||||
|
@ -2870,7 +2872,15 @@ fn make_tag_union_recursive_help<'a, 'b>(
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// take care to report a cyclic alias only once (not once for each alias in the cycle)
|
// take care to report a cyclic alias only once (not once for each alias in the cycle)
|
||||||
mark_cyclic_alias(env, typ, symbol, region, others, *can_report_cyclic_error);
|
mark_cyclic_alias(
|
||||||
|
env,
|
||||||
|
typ,
|
||||||
|
symbol,
|
||||||
|
alias_kind,
|
||||||
|
region,
|
||||||
|
others,
|
||||||
|
*can_report_cyclic_error,
|
||||||
|
);
|
||||||
*can_report_cyclic_error = false;
|
*can_report_cyclic_error = false;
|
||||||
|
|
||||||
Cyclic
|
Cyclic
|
||||||
|
@ -2882,6 +2892,7 @@ fn mark_cyclic_alias<'a>(
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
typ: &mut Type,
|
typ: &mut Type,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
|
alias_kind: AliasKind,
|
||||||
region: Region,
|
region: Region,
|
||||||
others: Vec<Symbol>,
|
others: Vec<Symbol>,
|
||||||
report: bool,
|
report: bool,
|
||||||
|
@ -2890,7 +2901,7 @@ fn mark_cyclic_alias<'a>(
|
||||||
*typ = Type::Erroneous(problem);
|
*typ = Type::Erroneous(problem);
|
||||||
|
|
||||||
if report {
|
if report {
|
||||||
let problem = Problem::CyclicAlias(symbol, region, others);
|
let problem = Problem::CyclicAlias(symbol, region, others, alias_kind);
|
||||||
env.problems.push(problem);
|
env.problems.push(problem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,12 +45,13 @@ pub enum Problem {
|
||||||
shadow: Loc<Ident>,
|
shadow: Loc<Ident>,
|
||||||
kind: ShadowKind,
|
kind: ShadowKind,
|
||||||
},
|
},
|
||||||
CyclicAlias(Symbol, Region, Vec<Symbol>),
|
CyclicAlias(Symbol, Region, Vec<Symbol>, AliasKind),
|
||||||
BadRecursion(Vec<CycleEntry>),
|
BadRecursion(Vec<CycleEntry>),
|
||||||
PhantomTypeArgument {
|
PhantomTypeArgument {
|
||||||
typ: Symbol,
|
typ: Symbol,
|
||||||
variable_region: Region,
|
variable_region: Region,
|
||||||
variable_name: Lowercase,
|
variable_name: Lowercase,
|
||||||
|
alias_kind: AliasKind,
|
||||||
},
|
},
|
||||||
UnboundTypeVariable {
|
UnboundTypeVariable {
|
||||||
typ: Symbol,
|
typ: Symbol,
|
||||||
|
|
|
@ -1322,6 +1322,7 @@ impl Type {
|
||||||
region,
|
region,
|
||||||
type_got: args.len() as u8,
|
type_got: args.len() as u8,
|
||||||
alias_needs: alias.type_variables.len() as u8,
|
alias_needs: alias.type_variables.len() as u8,
|
||||||
|
alias_kind: AliasKind::Structural,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2028,6 +2029,15 @@ pub enum AliasKind {
|
||||||
Opaque,
|
Opaque,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AliasKind {
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
AliasKind::Structural => "alias",
|
||||||
|
AliasKind::Opaque => "opaque",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct AliasVar {
|
pub struct AliasVar {
|
||||||
pub name: Lowercase,
|
pub name: Lowercase,
|
||||||
|
@ -2104,6 +2114,7 @@ pub enum Problem {
|
||||||
region: Region,
|
region: Region,
|
||||||
type_got: u8,
|
type_got: u8,
|
||||||
alias_needs: u8,
|
alias_needs: u8,
|
||||||
|
alias_kind: AliasKind,
|
||||||
},
|
},
|
||||||
InvalidModule,
|
InvalidModule,
|
||||||
SolvedTypeError,
|
SolvedTypeError,
|
||||||
|
|
|
@ -233,8 +233,10 @@ pub fn can_problem<'b>(
|
||||||
title = DUPLICATE_NAME.to_string();
|
title = DUPLICATE_NAME.to_string();
|
||||||
severity = Severity::RuntimeError;
|
severity = Severity::RuntimeError;
|
||||||
}
|
}
|
||||||
Problem::CyclicAlias(symbol, region, others) => {
|
Problem::CyclicAlias(symbol, region, others, alias_kind) => {
|
||||||
let answer = crate::error::r#type::cyclic_alias(alloc, lines, symbol, region, others);
|
let answer = crate::error::r#type::cyclic_alias(
|
||||||
|
alloc, lines, symbol, region, others, alias_kind,
|
||||||
|
);
|
||||||
|
|
||||||
doc = answer.0;
|
doc = answer.0;
|
||||||
title = answer.1;
|
title = answer.1;
|
||||||
|
@ -244,6 +246,7 @@ pub fn can_problem<'b>(
|
||||||
typ: alias,
|
typ: alias,
|
||||||
variable_region,
|
variable_region,
|
||||||
variable_name,
|
variable_name,
|
||||||
|
alias_kind,
|
||||||
} => {
|
} => {
|
||||||
doc = alloc.stack([
|
doc = alloc.stack([
|
||||||
alloc.concat([
|
alloc.concat([
|
||||||
|
@ -251,10 +254,12 @@ pub fn can_problem<'b>(
|
||||||
alloc.type_variable(variable_name),
|
alloc.type_variable(variable_name),
|
||||||
alloc.reflow(" type parameter is not used in the "),
|
alloc.reflow(" type parameter is not used in the "),
|
||||||
alloc.symbol_unqualified(alias),
|
alloc.symbol_unqualified(alias),
|
||||||
alloc.reflow(" alias definition:"),
|
alloc.reflow(" "),
|
||||||
|
alloc.reflow(alias_kind.as_str()),
|
||||||
|
alloc.reflow(" definition:"),
|
||||||
]),
|
]),
|
||||||
alloc.region(lines.convert_region(variable_region)),
|
alloc.region(lines.convert_region(variable_region)),
|
||||||
alloc.reflow("Roc does not allow unused type alias parameters!"),
|
alloc.reflow("Roc does not allow unused type parameters!"),
|
||||||
// TODO add link to this guide section
|
// TODO add link to this guide section
|
||||||
alloc.tip().append(alloc.reflow(
|
alloc.tip().append(alloc.reflow(
|
||||||
"If you want an unused type parameter (a so-called \"phantom type\"), \
|
"If you want an unused type parameter (a so-called \"phantom type\"), \
|
||||||
|
|
|
@ -77,6 +77,7 @@ pub fn type_problem<'b>(
|
||||||
region,
|
region,
|
||||||
type_got,
|
type_got,
|
||||||
alias_needs,
|
alias_needs,
|
||||||
|
alias_kind,
|
||||||
} => {
|
} => {
|
||||||
let needed_arguments = if alias_needs == 1 {
|
let needed_arguments = if alias_needs == 1 {
|
||||||
alloc.reflow("1 type argument")
|
alloc.reflow("1 type argument")
|
||||||
|
@ -92,7 +93,9 @@ pub fn type_problem<'b>(
|
||||||
alloc.concat([
|
alloc.concat([
|
||||||
alloc.reflow("The "),
|
alloc.reflow("The "),
|
||||||
alloc.symbol_unqualified(symbol),
|
alloc.symbol_unqualified(symbol),
|
||||||
alloc.reflow(" alias expects "),
|
alloc.reflow(" "),
|
||||||
|
alloc.reflow(alias_kind.as_str()),
|
||||||
|
alloc.reflow(" expects "),
|
||||||
needed_arguments,
|
needed_arguments,
|
||||||
alloc.reflow(", but it got "),
|
alloc.reflow(", but it got "),
|
||||||
found_arguments,
|
found_arguments,
|
||||||
|
@ -433,16 +436,21 @@ pub fn cyclic_alias<'b>(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
region: roc_region::all::Region,
|
region: roc_region::all::Region,
|
||||||
others: Vec<Symbol>,
|
others: Vec<Symbol>,
|
||||||
|
alias_kind: AliasKind,
|
||||||
) -> (RocDocBuilder<'b>, String) {
|
) -> (RocDocBuilder<'b>, String) {
|
||||||
let when_is_recursion_legal =
|
let when_is_recursion_legal =
|
||||||
alloc.reflow("Recursion in aliases is only allowed if recursion happens behind a tagged union, at least one variant of which is not recursive.");
|
alloc.reflow("Recursion in ")
|
||||||
|
.append(alloc.reflow(alias_kind.as_str()))
|
||||||
|
.append(alloc.reflow("es is only allowed if recursion happens behind a tagged union, at least one variant of which is not recursive."));
|
||||||
|
|
||||||
let doc = if others.is_empty() {
|
let doc = if others.is_empty() {
|
||||||
alloc.stack([
|
alloc.stack([
|
||||||
alloc
|
alloc
|
||||||
.reflow("The ")
|
.reflow("The ")
|
||||||
.append(alloc.symbol_unqualified(symbol))
|
.append(alloc.symbol_unqualified(symbol))
|
||||||
.append(alloc.reflow(" alias is self-recursive in an invalid way:")),
|
.append(alloc.reflow(" "))
|
||||||
|
.append(alloc.reflow(alias_kind.as_str()))
|
||||||
|
.append(alloc.reflow(" is self-recursive in an invalid way:")),
|
||||||
alloc.region(lines.convert_region(region)),
|
alloc.region(lines.convert_region(region)),
|
||||||
when_is_recursion_legal,
|
when_is_recursion_legal,
|
||||||
])
|
])
|
||||||
|
@ -451,14 +459,18 @@ pub fn cyclic_alias<'b>(
|
||||||
alloc
|
alloc
|
||||||
.reflow("The ")
|
.reflow("The ")
|
||||||
.append(alloc.symbol_unqualified(symbol))
|
.append(alloc.symbol_unqualified(symbol))
|
||||||
.append(alloc.reflow(" alias is recursive in an invalid way:")),
|
.append(alloc.reflow(" "))
|
||||||
|
.append(alloc.reflow(alias_kind.as_str()))
|
||||||
|
.append(alloc.reflow(" is recursive in an invalid way:")),
|
||||||
alloc.region(lines.convert_region(region)),
|
alloc.region(lines.convert_region(region)),
|
||||||
alloc
|
alloc
|
||||||
.reflow("The ")
|
.reflow("The ")
|
||||||
.append(alloc.symbol_unqualified(symbol))
|
.append(alloc.symbol_unqualified(symbol))
|
||||||
.append(alloc.reflow(
|
.append(alloc.reflow(" "))
|
||||||
" alias depends on itself through the following chain of definitions:",
|
.append(alloc.reflow(alias_kind.as_str()))
|
||||||
)),
|
.append(
|
||||||
|
alloc.reflow(" depends on itself through the following chain of definitions:"),
|
||||||
|
),
|
||||||
crate::report::cycle(
|
crate::report::cycle(
|
||||||
alloc,
|
alloc,
|
||||||
4,
|
4,
|
||||||
|
|
|
@ -3112,7 +3112,7 @@ mod test_reporting {
|
||||||
@r###"
|
@r###"
|
||||||
── TOO MANY TYPE ARGUMENTS ─────────────────────────────── /code/proj/Main.roc ─
|
── TOO MANY TYPE ARGUMENTS ─────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
The `Num` alias expects 1 type argument, but it got 2 instead:
|
The `Num` opaque expects 1 type argument, but it got 2 instead:
|
||||||
|
|
||||||
4│ a : Num.Num Num.I64 Num.F64
|
4│ a : Num.Num Num.I64 Num.F64
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -3134,7 +3134,7 @@ mod test_reporting {
|
||||||
@r###"
|
@r###"
|
||||||
── TOO MANY TYPE ARGUMENTS ─────────────────────────────── /code/proj/Main.roc ─
|
── TOO MANY TYPE ARGUMENTS ─────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
The `Num` alias expects 1 type argument, but it got 2 instead:
|
The `Num` opaque expects 1 type argument, but it got 2 instead:
|
||||||
|
|
||||||
4│ f : Str -> Num.Num Num.I64 Num.F64
|
4│ f : Str -> Num.Num Num.I64 Num.F64
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -3210,7 +3210,7 @@ mod test_reporting {
|
||||||
4│ Foo a : [Foo]
|
4│ Foo a : [Foo]
|
||||||
^
|
^
|
||||||
|
|
||||||
Roc does not allow unused type alias parameters!
|
Roc does not allow unused type parameters!
|
||||||
|
|
||||||
Tip: If you want an unused type parameter (a so-called "phantom
|
Tip: If you want an unused type parameter (a so-called "phantom
|
||||||
type"), read the guide section on phantom values.
|
type"), read the guide section on phantom values.
|
||||||
|
@ -10148,4 +10148,26 @@ All branches in an `if` must have the same type!
|
||||||
Tip: Looks like the y field is missing.
|
Tip: Looks like the y field is missing.
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
cyclic_opaque,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Recursive := [Infinitely Recursive]
|
||||||
|
|
||||||
|
0
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
── CYCLIC ALIAS ────────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
The `Recursive` opaque is self-recursive in an invalid way:
|
||||||
|
|
||||||
|
4│ Recursive := [Infinitely Recursive]
|
||||||
|
^^^^^^^^^
|
||||||
|
|
||||||
|
Recursion in opaquees is only allowed if recursion happens behind a
|
||||||
|
tagged union, at least one variant of which is not recursive.
|
||||||
|
"###
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue