diff --git a/embed/stdlib/contrib/RohanSreerama5/naiveBayesClassifier.fc b/embed/stdlib/contrib/RohanSreerama5/naiveBayesClassifier.fc index 5395000b4c..d8383db451 100644 Binary files a/embed/stdlib/contrib/RohanSreerama5/naiveBayesClassifier.fc and b/embed/stdlib/contrib/RohanSreerama5/naiveBayesClassifier.fc differ diff --git a/embed/stdlib/contrib/anaisdg/anomalydetection.fc b/embed/stdlib/contrib/anaisdg/anomalydetection.fc index 8637a5d83c..8cd3386e70 100644 Binary files a/embed/stdlib/contrib/anaisdg/anomalydetection.fc and b/embed/stdlib/contrib/anaisdg/anomalydetection.fc differ diff --git a/embed/stdlib/contrib/anaisdg/statsmodels.fc b/embed/stdlib/contrib/anaisdg/statsmodels.fc index fcd8ee4108..bd0220489d 100644 Binary files a/embed/stdlib/contrib/anaisdg/statsmodels.fc and b/embed/stdlib/contrib/anaisdg/statsmodels.fc differ diff --git a/embed/stdlib/contrib/bonitoo-io/alerta.fc b/embed/stdlib/contrib/bonitoo-io/alerta.fc index a64ae5cec9..2d10ee4e35 100644 Binary files a/embed/stdlib/contrib/bonitoo-io/alerta.fc and b/embed/stdlib/contrib/bonitoo-io/alerta.fc differ diff --git a/embed/stdlib/contrib/bonitoo-io/servicenow.fc b/embed/stdlib/contrib/bonitoo-io/servicenow.fc index 775eb6fb8a..f97f3e0d09 100644 Binary files a/embed/stdlib/contrib/bonitoo-io/servicenow.fc and b/embed/stdlib/contrib/bonitoo-io/servicenow.fc differ diff --git a/embed/stdlib/contrib/bonitoo-io/tickscript.fc b/embed/stdlib/contrib/bonitoo-io/tickscript.fc index f1cae075de..cd7038a514 100644 Binary files a/embed/stdlib/contrib/bonitoo-io/tickscript.fc and b/embed/stdlib/contrib/bonitoo-io/tickscript.fc differ diff --git a/embed/stdlib/contrib/bonitoo-io/victorops.fc b/embed/stdlib/contrib/bonitoo-io/victorops.fc index f52d1764cb..8a78326bd5 100644 Binary files a/embed/stdlib/contrib/bonitoo-io/victorops.fc and b/embed/stdlib/contrib/bonitoo-io/victorops.fc differ diff --git a/embed/stdlib/contrib/bonitoo-io/zenoss.fc b/embed/stdlib/contrib/bonitoo-io/zenoss.fc index 0a96a67769..77433a7ff5 100644 Binary files a/embed/stdlib/contrib/bonitoo-io/zenoss.fc and b/embed/stdlib/contrib/bonitoo-io/zenoss.fc differ diff --git a/embed/stdlib/contrib/chobbs/discord.fc b/embed/stdlib/contrib/chobbs/discord.fc index d79d964add..a26915c2c1 100644 Binary files a/embed/stdlib/contrib/chobbs/discord.fc and b/embed/stdlib/contrib/chobbs/discord.fc differ diff --git a/embed/stdlib/contrib/jsternberg/aggregate.fc b/embed/stdlib/contrib/jsternberg/aggregate.fc index 85e807526c..95474678b0 100644 Binary files a/embed/stdlib/contrib/jsternberg/aggregate.fc and b/embed/stdlib/contrib/jsternberg/aggregate.fc differ diff --git a/embed/stdlib/contrib/jsternberg/influxdb.fc b/embed/stdlib/contrib/jsternberg/influxdb.fc index 1e2d9486de..5f9fa0f368 100644 Binary files a/embed/stdlib/contrib/jsternberg/influxdb.fc and b/embed/stdlib/contrib/jsternberg/influxdb.fc differ diff --git a/embed/stdlib/contrib/jsternberg/math.fc b/embed/stdlib/contrib/jsternberg/math.fc index 87b85c9fce..5eafc9e49c 100644 Binary files a/embed/stdlib/contrib/jsternberg/math.fc and b/embed/stdlib/contrib/jsternberg/math.fc differ diff --git a/embed/stdlib/contrib/rhajek/bigpanda.fc b/embed/stdlib/contrib/rhajek/bigpanda.fc index 1d323e810c..727fc6b949 100644 Binary files a/embed/stdlib/contrib/rhajek/bigpanda.fc and b/embed/stdlib/contrib/rhajek/bigpanda.fc differ diff --git a/embed/stdlib/contrib/sranka/opsgenie.fc b/embed/stdlib/contrib/sranka/opsgenie.fc index 22a82318d1..e39ca467e8 100644 Binary files a/embed/stdlib/contrib/sranka/opsgenie.fc and b/embed/stdlib/contrib/sranka/opsgenie.fc differ diff --git a/embed/stdlib/contrib/sranka/sensu.fc b/embed/stdlib/contrib/sranka/sensu.fc index e80e7b2f77..e482a412bf 100644 Binary files a/embed/stdlib/contrib/sranka/sensu.fc and b/embed/stdlib/contrib/sranka/sensu.fc differ diff --git a/embed/stdlib/contrib/sranka/teams.fc b/embed/stdlib/contrib/sranka/teams.fc index ae686c9bb6..de6d6ce414 100644 Binary files a/embed/stdlib/contrib/sranka/teams.fc and b/embed/stdlib/contrib/sranka/teams.fc differ diff --git a/embed/stdlib/contrib/sranka/telegram.fc b/embed/stdlib/contrib/sranka/telegram.fc index 5e6aa0ba50..1cee77fb4b 100644 Binary files a/embed/stdlib/contrib/sranka/telegram.fc and b/embed/stdlib/contrib/sranka/telegram.fc differ diff --git a/embed/stdlib/contrib/sranka/webexteams.fc b/embed/stdlib/contrib/sranka/webexteams.fc index 04884298b6..7ca771f303 100644 Binary files a/embed/stdlib/contrib/sranka/webexteams.fc and b/embed/stdlib/contrib/sranka/webexteams.fc differ diff --git a/embed/stdlib/date.fc b/embed/stdlib/date.fc index ab51f7e83f..27bac49194 100644 Binary files a/embed/stdlib/date.fc and b/embed/stdlib/date.fc differ diff --git a/embed/stdlib/experimental.fc b/embed/stdlib/experimental.fc index 3e95d0579d..a2693f13f4 100644 Binary files a/embed/stdlib/experimental.fc and b/embed/stdlib/experimental.fc differ diff --git a/embed/stdlib/experimental/aggregate.fc b/embed/stdlib/experimental/aggregate.fc index f833d6b97b..a70088c63d 100644 Binary files a/embed/stdlib/experimental/aggregate.fc and b/embed/stdlib/experimental/aggregate.fc differ diff --git a/embed/stdlib/experimental/array.fc b/embed/stdlib/experimental/array.fc index 673e194cba..4c2cc1b960 100644 Binary files a/embed/stdlib/experimental/array.fc and b/embed/stdlib/experimental/array.fc differ diff --git a/embed/stdlib/experimental/csv.fc b/embed/stdlib/experimental/csv.fc index cf3be66b88..79b29acd4f 100644 Binary files a/embed/stdlib/experimental/csv.fc and b/embed/stdlib/experimental/csv.fc differ diff --git a/embed/stdlib/experimental/geo.fc b/embed/stdlib/experimental/geo.fc index 4b6e63736c..b7e6a83eea 100644 Binary files a/embed/stdlib/experimental/geo.fc and b/embed/stdlib/experimental/geo.fc differ diff --git a/embed/stdlib/experimental/oee.fc b/embed/stdlib/experimental/oee.fc index 7a71414b16..728a60945a 100644 Binary files a/embed/stdlib/experimental/oee.fc and b/embed/stdlib/experimental/oee.fc differ diff --git a/embed/stdlib/experimental/prometheus.fc b/embed/stdlib/experimental/prometheus.fc index 3d562de0b9..b2592f1e12 100644 Binary files a/embed/stdlib/experimental/prometheus.fc and b/embed/stdlib/experimental/prometheus.fc differ diff --git a/embed/stdlib/experimental/query.fc b/embed/stdlib/experimental/query.fc index af49c553e0..f7435056e2 100644 Binary files a/embed/stdlib/experimental/query.fc and b/embed/stdlib/experimental/query.fc differ diff --git a/embed/stdlib/experimental/usage.fc b/embed/stdlib/experimental/usage.fc index ae3bb84e9c..bc273a1a6c 100644 Binary files a/embed/stdlib/experimental/usage.fc and b/embed/stdlib/experimental/usage.fc differ diff --git a/embed/stdlib/http.fc b/embed/stdlib/http.fc index e20186e83f..61c1a4ba11 100644 Binary files a/embed/stdlib/http.fc and b/embed/stdlib/http.fc differ diff --git a/embed/stdlib/influxdata/influxdb/monitor.fc b/embed/stdlib/influxdata/influxdb/monitor.fc index e77984bd1d..ba981b417c 100644 Binary files a/embed/stdlib/influxdata/influxdb/monitor.fc and b/embed/stdlib/influxdata/influxdb/monitor.fc differ diff --git a/embed/stdlib/influxdata/influxdb/sample.fc b/embed/stdlib/influxdata/influxdb/sample.fc index c6e3d665d1..fdedb2bd15 100644 Binary files a/embed/stdlib/influxdata/influxdb/sample.fc and b/embed/stdlib/influxdata/influxdb/sample.fc differ diff --git a/embed/stdlib/influxdata/influxdb/schema.fc b/embed/stdlib/influxdata/influxdb/schema.fc index 375a756c1b..95ddb69e68 100644 Binary files a/embed/stdlib/influxdata/influxdb/schema.fc and b/embed/stdlib/influxdata/influxdb/schema.fc differ diff --git a/embed/stdlib/influxdata/influxdb/tasks.fc b/embed/stdlib/influxdata/influxdb/tasks.fc index 39be6aa03d..e4c1ab3b1e 100644 Binary files a/embed/stdlib/influxdata/influxdb/tasks.fc and b/embed/stdlib/influxdata/influxdb/tasks.fc differ diff --git a/embed/stdlib/influxdata/influxdb/v1.fc b/embed/stdlib/influxdata/influxdb/v1.fc index b87c5d4165..58e5228576 100644 Binary files a/embed/stdlib/influxdata/influxdb/v1.fc and b/embed/stdlib/influxdata/influxdb/v1.fc differ diff --git a/embed/stdlib/internal/promql.fc b/embed/stdlib/internal/promql.fc index e9d6be5d12..daa7137ca9 100644 Binary files a/embed/stdlib/internal/promql.fc and b/embed/stdlib/internal/promql.fc differ diff --git a/embed/stdlib/pagerduty.fc b/embed/stdlib/pagerduty.fc index 8ce07e0c60..6f159a267c 100644 Binary files a/embed/stdlib/pagerduty.fc and b/embed/stdlib/pagerduty.fc differ diff --git a/embed/stdlib/pushbullet.fc b/embed/stdlib/pushbullet.fc index ea869353d1..f777ab3d24 100644 Binary files a/embed/stdlib/pushbullet.fc and b/embed/stdlib/pushbullet.fc differ diff --git a/embed/stdlib/sampledata.fc b/embed/stdlib/sampledata.fc index 94f7f6891c..2c4f746c5d 100644 Binary files a/embed/stdlib/sampledata.fc and b/embed/stdlib/sampledata.fc differ diff --git a/embed/stdlib/slack.fc b/embed/stdlib/slack.fc index 4031dd10e5..fa4ef0a646 100644 Binary files a/embed/stdlib/slack.fc and b/embed/stdlib/slack.fc differ diff --git a/embed/stdlib/testing.fc b/embed/stdlib/testing.fc index 6b6c7fcb21..225c44a4c8 100644 Binary files a/embed/stdlib/testing.fc and b/embed/stdlib/testing.fc differ diff --git a/embed/stdlib/timezone.fc b/embed/stdlib/timezone.fc index 33ed7e21f1..ae6bcd315f 100644 Binary files a/embed/stdlib/timezone.fc and b/embed/stdlib/timezone.fc differ diff --git a/embed/stdlib/universe.fc b/embed/stdlib/universe.fc index f958c21a4c..13c20b02c4 100644 Binary files a/embed/stdlib/universe.fc and b/embed/stdlib/universe.fc differ diff --git a/libflux/flux-core/src/semantic/convert.rs b/libflux/flux-core/src/semantic/convert.rs index bd1a25391b..f59b7dad28 100644 --- a/libflux/flux-core/src/semantic/convert.rs +++ b/libflux/flux-core/src/semantic/convert.rs @@ -610,20 +610,9 @@ impl<'a> Converter<'a> { for con in &type_expression.constraints { if con.tvar.name == name { for k in &con.kinds { - match k.name.as_str() { - "Addable" => kinds.push(types::Kind::Addable), - "Subtractable" => kinds.push(types::Kind::Subtractable), - "Divisible" => kinds.push(types::Kind::Divisible), - "Numeric" => kinds.push(types::Kind::Numeric), - "Comparable" => kinds.push(types::Kind::Comparable), - "Equatable" => kinds.push(types::Kind::Equatable), - "Nullable" => kinds.push(types::Kind::Nullable), - "Negatable" => kinds.push(types::Kind::Negatable), - "Timeable" => kinds.push(types::Kind::Timeable), - "Record" => kinds.push(types::Kind::Record), - "Basic" => kinds.push(types::Kind::Basic), - "Stringable" => kinds.push(types::Kind::Stringable), - _ => { + match k.name.parse() { + Ok(kind) => kinds.push(kind), + Err(()) => { self.errors.push(located( k.base.location.clone(), ErrorKind::InvalidConstraint(k.name.clone()), @@ -770,7 +759,7 @@ impl<'a> Converter<'a> { Ok(FunctionExpr { loc: expr.base.location, - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, params, body, vectorized: None, @@ -958,7 +947,7 @@ impl<'a> Converter<'a> { }?; Ok(CallExpr { loc: expr.base.location, - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, callee, arguments, pipe: None, @@ -974,7 +963,7 @@ impl<'a> Converter<'a> { let property = self.symbols.lookup_property_key(&property); Ok(MemberExpr { loc: expr.base.location, - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, object, property, }) @@ -985,7 +974,7 @@ impl<'a> Converter<'a> { let index = self.convert_expression(expr.index)?; Ok(IndexExpr { loc: expr.base.location, - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, array, index, }) @@ -1003,7 +992,7 @@ impl<'a> Converter<'a> { let right = self.convert_expression(expr.right)?; Ok(BinaryExpr { loc: expr.base.location, - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, operator: expr.operator, left, right, @@ -1014,7 +1003,7 @@ impl<'a> Converter<'a> { let argument = self.convert_expression(expr.argument)?; Ok(UnaryExpr { loc: expr.base.location, - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, operator: expr.operator, argument, }) @@ -1043,6 +1032,7 @@ impl<'a> Converter<'a> { test, consequent, alternate, + typ: MonoType::Error, }) } @@ -1058,7 +1048,7 @@ impl<'a> Converter<'a> { }; Ok(ObjectExpr { loc: expr.base.location, - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, with, properties, }) @@ -1080,7 +1070,7 @@ impl<'a> Converter<'a> { Some(expr) => self.convert_expression(expr)?, None => Expression::Identifier(IdentifierExpr { loc: key.loc.clone(), - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, name: self .symbols .lookup_option(&key.name) @@ -1102,7 +1092,7 @@ impl<'a> Converter<'a> { .collect::>>()?; Ok(ArrayExpr { loc: expr.base.location, - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, elements, }) } @@ -1117,7 +1107,7 @@ impl<'a> Converter<'a> { } Ok(DictExpr { loc: expr.base.location, - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, elements, }) } @@ -1150,7 +1140,7 @@ impl<'a> Converter<'a> { fn convert_identifier_expression(&mut self, id: ast::Identifier) -> Result { Ok(IdentifierExpr { - typ: MonoType::Var(self.sub.fresh()), + typ: MonoType::Error, name: self.symbols.lookup(&id.name), loc: id.base.location, }) diff --git a/libflux/flux-core/src/semantic/flatbuffers/tests.rs b/libflux/flux-core/src/semantic/flatbuffers/tests.rs index 1563e09cae..787ab20dbe 100644 --- a/libflux/flux-core/src/semantic/flatbuffers/tests.rs +++ b/libflux/flux-core/src/semantic/flatbuffers/tests.rs @@ -6,14 +6,15 @@ use chrono::FixedOffset; use super::semantic_generated::fbsemantic; use crate::{ - ast, semantic, + ast, semantic::{ - convert, + self, convert, env::Environment, import::Packages, nodes::{FunctionExpr, Package}, sub, - walk::{walk, Node}, + types::{MonoType, Tvar}, + walk::{walk, walk_mut, Node, NodeMut}, Analyzer, }, }; @@ -105,6 +106,29 @@ re !~ /foo/ return; } }; + + // We can't serialize the error types so replace any `typ` fields with a dummy variable instead + walk_mut( + &mut |n: &mut NodeMut<'_>| { + let typ = match n { + NodeMut::ArrayExpr(a) => &mut a.typ, + NodeMut::DictExpr(a) => &mut a.typ, + NodeMut::FunctionExpr(a) => &mut a.typ, + NodeMut::BinaryExpr(a) => &mut a.typ, + NodeMut::CallExpr(a) => &mut a.typ, + NodeMut::ConditionalExpr(a) => &mut a.typ, + NodeMut::MemberExpr(a) => &mut a.typ, + NodeMut::IndexExpr(a) => &mut a.typ, + NodeMut::ObjectExpr(a) => &mut a.typ, + NodeMut::UnaryExpr(a) => &mut a.typ, + NodeMut::IdentifierExpr(a) => &mut a.typ, + _ => return, + }; + *typ = MonoType::Var(Tvar(0)); + }, + &mut NodeMut::Package(&mut pkg), + ); + let (vec, offset) = match super::serialize_pkg(&mut pkg) { Ok((v, o)) => (v, o), Err(e) => { diff --git a/libflux/flux-core/src/semantic/formatter/mod.rs b/libflux/flux-core/src/semantic/formatter/mod.rs index a42d4e8807..599e34f8a2 100644 --- a/libflux/flux-core/src/semantic/formatter/mod.rs +++ b/libflux/flux-core/src/semantic/formatter/mod.rs @@ -647,7 +647,7 @@ impl Formatter { self.unindent(); } self.write_rune(')'); - self.write_string(&format!(":{}", &n.consequent.type_of())); + self.write_string(&format!(":{}", &n.typ)); } fn format_member_assignment(&mut self, n: &semantic::nodes::MemberAssgn) { diff --git a/libflux/flux-core/src/semantic/formatter/tests.rs b/libflux/flux-core/src/semantic/formatter/tests.rs index 24c142fb6b..964cb9215b 100644 --- a/libflux/flux-core/src/semantic/formatter/tests.rs +++ b/libflux/flux-core/src/semantic/formatter/tests.rs @@ -114,16 +114,16 @@ fn format_function_expression() { expect![[r#" package main (a) => { - return a:t19 - }:(a:t19) => t19 + return a:A + }:(a:A) => A f = (a, b=1) => { - return a:t21 +:t21 b:t21 - }:(a:t21, ?b:t21) => t21 + return a:C +:C b:C + }:(a:C, ?b:C) => C x = f:(a:int, ?b:int) => int(a: 2):int y = f:(a:int, ?b:int) => int(a: x:int, b: f:(a:int, ?b:int) => int(a: x:int):int):int g = (t) => { - return t:t28 - }:(<-t:t28) => t28"#]], + return t:t12 + }:(<-t:t12) => t12"#]], ) } @@ -265,8 +265,8 @@ fn format_block_statement() { expect![[r#" package main (r) => { - v = (if r:J <:bool 0 then -r:J:J else r:J):J - return v:J *:J v:J - }:(r:J) => J"#]], + v = (if r:A <:bool 0 then -r:A:A else r:A):A + return v:A *:A v:A + }:(r:A) => A"#]], ) } diff --git a/libflux/flux-core/src/semantic/infer.rs b/libflux/flux-core/src/semantic/infer.rs index 229dcd15e2..1ddfd07ad2 100644 --- a/libflux/flux-core/src/semantic/infer.rs +++ b/libflux/flux-core/src/semantic/infer.rs @@ -173,7 +173,7 @@ pub fn equal( act: &MonoType, loc: &SourceLocation, sub: &mut Substitution, -) -> Result<(), Located>> { +) -> Result>> { log::debug!("Constraint::Equal {:?}: {} <===> {}", loc.source, exp, act); exp.try_unify(act, sub).map_err(|error| Located { location: loc.clone(), diff --git a/libflux/flux-core/src/semantic/nodes.rs b/libflux/flux-core/src/semantic/nodes.rs index 93a28ea11b..f11cfe9a9e 100644 --- a/libflux/flux-core/src/semantic/nodes.rs +++ b/libflux/flux-core/src/semantic/nodes.rs @@ -163,13 +163,17 @@ impl InferState<'_, '_> { } } - fn equal(&mut self, exp: &MonoType, act: &MonoType, loc: &ast::SourceLocation) { - if let Err(err) = infer::equal(exp, act, loc, self.sub) { - self.errors - .extend(err.error.into_iter().map(|error| Located { - location: loc.clone(), - error: error.into(), - })); + fn equal(&mut self, exp: &MonoType, act: &MonoType, loc: &ast::SourceLocation) -> MonoType { + match infer::equal(exp, act, loc, self.sub) { + Ok(typ) => typ, + Err(err) => { + self.errors + .extend(err.error.into_iter().map(|error| Located { + location: loc.clone(), + error: error.into(), + })); + MonoType::Error + } } } @@ -272,7 +276,7 @@ impl Expression { Expression::Binary(e) => e.typ.clone(), Expression::Unary(e) => e.typ.clone(), Expression::Call(e) => e.typ.clone(), - Expression::Conditional(e) => e.alternate.type_of(), + Expression::Conditional(e) => e.typ.clone(), Expression::StringExpr(_) => MonoType::STRING, Expression::Integer(_) => MonoType::INT, Expression::Float(_) => MonoType::FLOAT, @@ -859,7 +863,9 @@ impl ArrayExpr { None => { elt = Some(el.type_of()); } - Some(elt) => infer.equal(elt, &el.type_of(), el.loc()), + Some(elt) => { + infer.equal(elt, &el.type_of(), el.loc()); + } } } let elt = elt.unwrap_or_else(|| MonoType::Var(infer.sub.fresh())); @@ -1303,20 +1309,9 @@ impl BinaryExpr { let binop_arithmetic_constraints = |this: &mut BinaryExpr, infer: &mut InferState<'_, '_>, kind| { let left = this.left.type_of(); - this.typ = left.clone(); - infer.solve(&[ - Constraint::Equal { - exp: left.clone(), - act: this.right.type_of(), - loc: this.right.loc().clone(), - }, - Constraint::Kind { - act: left, - exp: kind, - loc: this.loc.clone(), - }, - ]); + this.typ = infer.equal(&left, &this.right.type_of(), this.right.loc()); + infer.constrain(kind, &left, &this.loc); }; let binop_compare_constraints = |this: &mut BinaryExpr, infer: &mut InferState<'_, '_>, kind| { @@ -1432,6 +1427,7 @@ pub struct CallExpr { impl CallExpr { fn infer(&mut self, infer: &mut InferState<'_, '_>) -> Result { + self.typ = MonoType::Var(infer.sub.fresh()); // First, recursively infer every type of the children of this call expression, // update the environment and the constraints, and use the inferred types to // build the fields of the type for this call expression. @@ -1524,25 +1520,23 @@ pub struct ConditionalExpr { pub test: Expression, pub consequent: Expression, pub alternate: Expression, + pub typ: MonoType, } impl ConditionalExpr { fn infer(&mut self, infer: &mut InferState<'_, '_>) -> Result { self.test.infer(infer)?; + infer.equal(&MonoType::BOOL, &self.test.type_of(), self.test.loc()); + self.consequent.infer(infer)?; self.alternate.infer(infer)?; - infer.solve(&[ - Constraint::Equal { - exp: MonoType::BOOL, - act: self.test.type_of(), - loc: self.test.loc().clone(), - }, - Constraint::Equal { - exp: self.consequent.type_of(), - act: self.alternate.type_of(), - loc: self.alternate.loc().clone(), - }, - ]); + + self.typ = infer.equal( + &self.consequent.type_of(), + &self.alternate.type_of(), + self.alternate.loc(), + ); + Ok(()) } fn apply(mut self, sub: &Substitution) -> Self { @@ -1620,6 +1614,7 @@ impl MemberExpr { } let r = { + self.typ = MonoType::Var(infer.sub.fresh()); let head = types::Property { k: Label::from(self.property.to_owned()), v: self.typ.to_owned(), @@ -1659,6 +1654,8 @@ impl IndexExpr { self.array.infer(infer)?; self.index.infer(infer)?; + self.typ = MonoType::Var(infer.sub.fresh()); + infer.solve(&[ Constraint::Equal { act: self.index.type_of(), diff --git a/libflux/flux-core/src/semantic/tests/vectorize.rs b/libflux/flux-core/src/semantic/tests/vectorize.rs index 2cf22a4ccc..a429076fb3 100644 --- a/libflux/flux-core/src/semantic/tests/vectorize.rs +++ b/libflux/flux-core/src/semantic/tests/vectorize.rs @@ -36,8 +36,8 @@ fn vectorize_field_access() -> anyhow::Result<()> { expect_test::expect![[r#" (r) => { - return {a: r:{J with b:v[D], a:v[B]}.a:v[B], b: r:{J with b:v[D], a:v[B]}.b:v[D]}:{a:v[B], b:v[D]} - }:(r:{J with b:D, a:B}) => {a:B, b:D}"#]].assert_eq(&crate::semantic::formatter::format_node( + return {a: r:{F with b:v[B], a:v[D]}.a:v[D], b: r:{F with b:v[B], a:v[D]}.b:v[B]}:{a:v[D], b:v[B]} + }:(r:{F with b:B, a:D}) => {a:D, b:B}"#]].assert_eq(&crate::semantic::formatter::format_node( Node::FunctionExpr(function), )?); @@ -52,8 +52,8 @@ fn vectorize_with_construction() -> anyhow::Result<()> { expect_test::expect![[r#" (r) => { - return {r:{G with a:v[B]} with b: r:{G with a:v[B]}.a:v[B]}:{G with b:v[B], a:v[B]} - }:(r:{G with a:B}) => {G with b:B, a:B}"#]] + return {r:{C with a:v[B]} with b: r:{C with a:v[B]}.a:v[B]}:{C with b:v[B], a:v[B]} + }:(r:{C with a:B}) => {C with b:B, a:B}"#]] .assert_eq(&crate::semantic::formatter::format_node( Node::FunctionExpr(function), )?); diff --git a/libflux/flux-core/src/semantic/types.rs b/libflux/flux-core/src/semantic/types.rs index fc6be4624b..720d9715ce 100644 --- a/libflux/flux-core/src/semantic/types.rs +++ b/libflux/flux-core/src/semantic/types.rs @@ -5,6 +5,7 @@ use std::{ collections::{BTreeMap, BTreeSet}, fmt::{self, Write}, hash::Hash, + str::FromStr, }; use codespan_reporting::diagnostic; @@ -31,6 +32,23 @@ struct Unifier<'a, E = Error> { errors: Errors, } +impl<'a, E> Unifier<'a, E> { + fn new(sub: &'a mut Substitution) -> Self { + Unifier { + sub, + errors: Errors::new(), + } + } + + fn finish(self, value: T) -> Result> { + if self.errors.has_errors() { + Err(self.errors) + } else { + Ok(value) + } + } +} + /// A type scheme that quantifies the free variables of a monotype. #[derive(Debug, Clone)] pub struct PolyType { @@ -370,6 +388,28 @@ pub enum Kind { Timeable, } +impl FromStr for Kind { + type Err = (); + + fn from_str(name: &str) -> Result { + Ok(match name { + "Addable" => Kind::Addable, + "Subtractable" => Kind::Subtractable, + "Divisible" => Kind::Divisible, + "Numeric" => Kind::Numeric, + "Comparable" => Kind::Comparable, + "Equatable" => Kind::Equatable, + "Nullable" => Kind::Nullable, + "Negatable" => Kind::Negatable, + "Timeable" => Kind::Timeable, + "Record" => Kind::Record, + "Basic" => Kind::Basic, + "Stringable" => Kind::Stringable, + _ => return Err(()), + }) + } +} + /// Pointer type used in `MonoType` pub type Ptr = std::sync::Arc; @@ -755,26 +795,19 @@ impl MonoType { &self, // self represents the expected type actual: &Self, sub: &mut Substitution, - ) -> Result<(), Errors> { - let mut unifier = Unifier { - sub, - errors: Errors::new(), - }; + ) -> Result> { + let mut unifier = Unifier::new(sub); - self.unify(actual, &mut unifier); + let typ = self.unify(actual, &mut unifier); - if unifier.errors.has_errors() { - Err(unifier.errors) - } else { - Ok(()) - } + unifier.finish(typ) } fn unify( &self, // self represents the expected type actual: &Self, unifier: &mut Unifier<'_>, - ) { + ) -> MonoType { log::debug!("Unify {} <=> {}", self, actual); match (self, actual) { // An error has already occurred so assume everything is ok here so that we do not @@ -783,18 +816,28 @@ impl MonoType { (MonoType::Builtin(exp), MonoType::Builtin(act)) => exp.unify(*act, unifier), (MonoType::Var(tv), MonoType::Var(tv2)) => { match (unifier.sub.try_apply(*tv), unifier.sub.try_apply(*tv2)) { - (Some(self_), Some(actual)) => self_.unify(&actual, unifier), - (Some(self_), None) => self_.unify(&MonoType::Var(*tv2), unifier), - (None, Some(actual)) => MonoType::Var(*tv).unify(&actual, unifier), + (Some(self_), Some(actual)) => { + self_.unify(&actual, unifier); + } + (Some(self_), None) => { + self_.unify(&MonoType::Var(*tv2), unifier); + } + (None, Some(actual)) => { + MonoType::Var(*tv).unify(&actual, unifier); + } (None, None) => tv.unify(&MonoType::Var(*tv2), unifier), } } (MonoType::Var(tv), t) => match unifier.sub.try_apply(*tv) { - Some(typ) => typ.unify(t, unifier), + Some(typ) => { + typ.unify(t, unifier); + } None => tv.unify(t, unifier), }, (t, MonoType::Var(tv)) => match unifier.sub.try_apply(*tv) { - Some(typ) => t.unify(&typ, unifier), + Some(typ) => { + t.unify(&typ, unifier); + } None => tv.unify(t, unifier), }, (MonoType::Arr(t), MonoType::Arr(s)) => t.unify(s, unifier), @@ -809,6 +852,7 @@ impl MonoType { }); } } + self.clone() } /// Validates that the current type meets the constraints of the specified kind. @@ -991,7 +1035,7 @@ impl MaxTvar for Array { impl Array { // self represents the expected type. fn unify(&self, with: &Self, unifier: &mut Unifier<'_>) { - self.0.unify(&with.0, unifier) + self.0.unify(&with.0, unifier); } fn constrain(&self, with: Kind, cons: &mut TvarKinds) -> Result<(), Error> { @@ -1032,7 +1076,7 @@ impl MaxTvar for Vector { impl Vector { // self represents the expected type. fn unify(&self, with: &Self, unifier: &mut Unifier<'_>) { - self.0.unify(&with.0, unifier) + self.0.unify(&with.0, unifier); } fn constrain(&self, with: Kind, cons: &mut TvarKinds) -> Result<(), Error> { @@ -1073,7 +1117,7 @@ impl MaxTvar for Dictionary { impl Dictionary { fn unify(&self, actual: &Self, unifier: &mut Unifier<'_>) { self.key.unify(&actual.key, unifier); - self.val.unify(&actual.val, unifier) + self.val.unify(&actual.val, unifier); } fn constrain(&self, with: Kind, _: &mut TvarKinds) -> Result<(), Error> { @@ -1296,7 +1340,7 @@ impl Record { }, ) if a == b => { t.unify(u, unifier); - l.unify(r, unifier) + l.unify(r, unifier); } ( Record::Extension { @@ -1324,7 +1368,7 @@ impl Record { tail: MonoType::Var(var), }); l.unify(&act, unifier); - exp.unify(r, unifier) + exp.unify(r, unifier); } // If we are expecting {a: u | r} but find {}, label `a` is missing. ( @@ -1746,11 +1790,7 @@ impl Function { self.unify(actual, &mut unifier); - if unifier.errors.has_errors() { - Err(unifier.errors) - } else { - Ok(()) - } + unifier.finish(()) } /// Given two function types f and g, the process for unifying their arguments is as follows: diff --git a/libflux/flux-core/src/semantic/walk/walk_mut.rs b/libflux/flux-core/src/semantic/walk/walk_mut.rs index 82fc57ab57..89d6cb1b74 100644 --- a/libflux/flux-core/src/semantic/walk/walk_mut.rs +++ b/libflux/flux-core/src/semantic/walk/walk_mut.rs @@ -658,10 +658,7 @@ mod tests { mod mutate_nodes { use super::*; - use crate::{ - map::HashSet, - semantic::types::{MonoType, Tvar}, - }; + use crate::semantic::types::{MonoType, Tvar}; // LocationCollector collects the locations found in the graph while walking. struct LocationCollector { @@ -683,7 +680,7 @@ mod tests { // TypeCollector collects the types found in the graph while walking. struct TypeCollector { - types: Vec, + types: Vec, } impl TypeCollector { @@ -741,8 +738,8 @@ mod tests { NodeMut::RegexpLit(n) => Some(Expression::Regexp((*n).clone()).type_of()), _ => None, }; - if let Some(MonoType::Var(tv)) = typ { - self.types.push(tv); + if let Some(typ) = typ { + self.types.push(typ); } true } @@ -803,12 +800,8 @@ join(tables:[a,b], on:["t1"], fn: (a,b) => (a["_field"] - b["_field"]) / b["_fie walk_mut(&mut v, &mut NodeMut::Package(&mut pkg)); let types = v.types; assert!(types.len() > 0); - // every tvar has a unique id - let mut ids: HashSet = HashSet::new(); - for tvar in types { - assert!(!ids.contains(&tvar.0)); - ids.insert(tvar.0); - } + // no type is a type variable + assert!(types.iter().all(|t| !matches!(t, MonoType::Var(_)))); // now mutate the types walk_mut( &mut |n: &mut NodeMut| { @@ -833,7 +826,9 @@ join(tables:[a,b], on:["t1"], fn: (a,b) => (a["_field"] - b["_field"]) / b["_fie let types = v.types; assert!(types.len() > 0); for tvar in types { - assert_eq!(tvar, Tvar(1234)); + if let MonoType::Var(tvar) = tvar { + assert_eq!(tvar, Tvar(1234)); + } } } } diff --git a/libflux/go/libflux/buildinfo.gen.go b/libflux/go/libflux/buildinfo.gen.go index 36b8f2f157..657e83276e 100644 --- a/libflux/go/libflux/buildinfo.gen.go +++ b/libflux/go/libflux/buildinfo.gen.go @@ -40,24 +40,24 @@ var sourceHashes = map[string]string{ "libflux/flux-core/src/scanner/unicode.rl.COPYING": "6cf2d5d26d52772ded8a5f0813f49f83dfa76006c5f398713be3854fe7bc4c7e", "libflux/flux-core/src/semantic/bootstrap.rs": "b6cac4067283f3a37192867ae9be4c5ca6d6391a180a36a0851d7c0818660917", "libflux/flux-core/src/semantic/check.rs": "026f979f64807aa5dcd1bffe3d885db86287cba42161c0dc864ef7a457b381f6", - "libflux/flux-core/src/semantic/convert.rs": "a72874d771cc591152b904aa6f2c6d8d537e18cf829c7222fb7f321ed61f7028", + "libflux/flux-core/src/semantic/convert.rs": "2872085503e89a36ef53f6eaa9e054f6a2dd3e0acb3df20442ca96cb30f6282c", "libflux/flux-core/src/semantic/env.rs": "825089bae3c0e0696c49fead36570c03f197c49d3b01717d90ffc3c5472bd761", "libflux/flux-core/src/semantic/flatbuffers/mod.rs": "69ed1d057ba284732d7fa1400bfbcb66e8f6dd54dd08ae6fa2732275a7b0f89b", "libflux/flux-core/src/semantic/flatbuffers/semantic_generated.rs": "493bf5a623157dba48b659fab7d335854a0b8c117b325deb9abcd3898fb07c02", "libflux/flux-core/src/semantic/flatbuffers/types.rs": "aebd046a8dd73003a7a5f6df5cf7b5a350c67eec083758f4683cf4438f2cd56a", - "libflux/flux-core/src/semantic/formatter/mod.rs": "877f42aaa7a250725bd4288aa9f4d40b7a570fe2c4dd1dd1e94fa9da9fbfede8", + "libflux/flux-core/src/semantic/formatter/mod.rs": "1ea36316ee71f6a3e97f1d833b119a1cd06072c11809967a3316e718a0a8f4ab", "libflux/flux-core/src/semantic/fresh.rs": "a56bd5b72b61b1b859af8ae03ee4b6f3ad9979463af77721e912e035f9bc2cc4", "libflux/flux-core/src/semantic/fs.rs": "f7f609bc8149769d99b737150e184a2d54029c0b768365dbcf08ff193b0e1f6f", "libflux/flux-core/src/semantic/import.rs": "73adc35c735c317af0fa7625e77a58f6824667d8e59f35c7d05687bd02d79a84", - "libflux/flux-core/src/semantic/infer.rs": "45bd643ea187b58b12d95d485e4678369201aa4b4b2fcae7acb96c7de8d518ac", + "libflux/flux-core/src/semantic/infer.rs": "4ae48d87b1051bae56c2884958a8beb9bbce2877e49a235da8717d62c4c3281c", "libflux/flux-core/src/semantic/mod.rs": "5f421c767192cb8915daea9d2ab01a7cc2d607a2f0f6dd8dff3c65c4ff67736b", - "libflux/flux-core/src/semantic/nodes.rs": "5e09dc023d74f6a5b5b38992bcfd7afdf444bc47ed0f105ba33c2a10806e590e", + "libflux/flux-core/src/semantic/nodes.rs": "6303e917f57d8289fe7ebc8e51e69111906d16cba0c06dc8475d2a9c8059410d", "libflux/flux-core/src/semantic/sub.rs": "7b4aa4230019e1e8a684f875ca27427578df5ac97530abb2f318164467dcd6eb", - "libflux/flux-core/src/semantic/types.rs": "b3d1a2e6e4030dd770780c222a5d0870627d19395eddfcb4d87a27a72f000ab7", + "libflux/flux-core/src/semantic/types.rs": "044fd63851a7e4e02fa26fbe69e30f540640f332605d01a5bbbe200ddc3740b1", "libflux/flux-core/src/semantic/walk/_walk.rs": "03a862d35eac8b74cdc7fae0a91ae155859ac02e1b32aa5d503f523188fc5fde", "libflux/flux-core/src/semantic/walk/mod.rs": "2d44af6df22c6b93f5155c15cffd28be940f45668883c9b2d4a1184a72a68c68", "libflux/flux-core/src/semantic/walk/test_utils.rs": "b5e87dca838e4a773b624bca8e9b13f1b4c756277ac308612822193abde2857d", - "libflux/flux-core/src/semantic/walk/walk_mut.rs": "015753709a25f8c172ef071eb9cbb191410617c0e55efd61ae10aec035e4cab5", + "libflux/flux-core/src/semantic/walk/walk_mut.rs": "0d2482aeb8d270fdf09627577f921e841ee48803e4c5cc0c5ed3a88bc7709a67", "libflux/flux/Cargo.toml": "5db86e159c170bc82c1288d3b2190bd44498f6a212ee9025a78014400c3e3ef6", "libflux/flux/FLUXDOC.md": "92e6dd8043bd87b4924e09aa28fb5346630aee1214de28ea2c8fc0687cad0785", "libflux/flux/build.rs": "c3257f0014596c8f41396a115ffef11413aebd52006ec5fd5b7fc81cbe82ebd0",