Returns the type of a relation expression or a type error. This function is careful to check validity, not just find out the type. It should be linear in the size of the AST. ??? should we also compute keys and return a `ReprRelationType`? ggevay: Checking keys would have the same problem as checking nullability: key inference is very heuristic (even more so than nullability inference), so it's
(
&self,
expr: &'a MirRelationExpr,
ctx: &Context,
)
| 882 | /// is very heuristic (even more so than nullability inference), so it's almost impossible to |
| 883 | /// reliably keep it stable across transformations. |
| 884 | pub fn typecheck<'a>( |
| 885 | &self, |
| 886 | expr: &'a MirRelationExpr, |
| 887 | ctx: &Context, |
| 888 | ) -> Result<Vec<ReprColumnType>, TypeError<'a>> { |
| 889 | use MirRelationExpr::*; |
| 890 | |
| 891 | self.checked_recur(|tc| match expr { |
| 892 | Constant { typ, rows } => { |
| 893 | if let Ok(rows) = rows { |
| 894 | for (row, _id) in rows { |
| 895 | let datums = row.unpack(); |
| 896 | |
| 897 | let col_types = typ |
| 898 | .column_types |
| 899 | .iter() |
| 900 | .cloned() |
| 901 | .collect_vec(); |
| 902 | row_difference_with_column_types( |
| 903 | expr, &datums, &col_types, |
| 904 | )?; |
| 905 | |
| 906 | if self.disallow_dummy |
| 907 | && datums.iter().any(|d| d == &mz_repr::Datum::Dummy) |
| 908 | { |
| 909 | return Err(TypeError::DisallowedDummy { |
| 910 | source: expr, |
| 911 | }); |
| 912 | } |
| 913 | } |
| 914 | } |
| 915 | |
| 916 | Ok(typ.column_types.iter().cloned().collect_vec()) |
| 917 | } |
| 918 | Get { typ, id, .. } => { |
| 919 | if let Id::Global(_global_id) = id { |
| 920 | if !ctx.contains_key(id) { |
| 921 | // TODO(mgree) pass QueryContext through to check these types |
| 922 | return Ok(typ.column_types.iter().cloned().collect_vec()); |
| 923 | } |
| 924 | } |
| 925 | |
| 926 | let ctx_typ = ctx.get(id).ok_or_else(|| TypeError::Unbound { |
| 927 | source: expr, |
| 928 | id: id.clone(), |
| 929 | typ: typ.clone(), |
| 930 | })?; |
| 931 | |
| 932 | let column_types = typ.column_types.iter().cloned().collect_vec(); |
| 933 | |
| 934 | // covariant: the ascribed type must be a subtype of the actual type in the context |
| 935 | let diffs = relation_subtype_difference(&column_types, ctx_typ) |
| 936 | .into_iter() |
| 937 | .flat_map(|diff| diff.ignore_nullability()) |
| 938 | .collect::<Vec<_>>(); |
| 939 | |
| 940 | if !diffs.is_empty() { |
| 941 | return Err(TypeError::MismatchColumns { |