From e77e53f37b5bff99e8b427ef8ac11a49b7802aa2 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 9 Aug 2022 08:48:21 -0700 Subject: [PATCH] Enable optional record field underivable error --- crates/compiler/solve/src/ability.rs | 27 ++++++++++++++------------- crates/reporting/src/error/type.rs | 4 +++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index bc4bfdb794..f63ebd414c 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -4,7 +4,9 @@ use roc_collections::{VecMap, VecSet}; use roc_error_macros::{internal_error, todo_abilities}; use roc_module::symbol::Symbol; use roc_region::all::{Loc, Region}; -use roc_solve_problem::{NotDerivableContext, TypeError, UnderivableReason, Unfulfilled}; +use roc_solve_problem::{ + NotDerivableContext, NotDerivableDecode, TypeError, UnderivableReason, Unfulfilled, +}; use roc_types::num::NumericRange; use roc_types::subs::{ instantiate_rigids, Content, FlatType, GetSubsSlice, Rank, RecordFields, Subs, Variable, @@ -837,19 +839,18 @@ impl DerivableVisitor for DeriveDecoding { var: Variable, fields: RecordFields, ) -> Result { - let has_optional_field = subs - .get_subs_slice(fields.record_fields()) - .iter() - .any(|field| matches!(field, RecordField::Optional(..))); - - if has_optional_field { - Err(NotDerivable { - var, - context: NotDerivableContext::NoContext, - }) - } else { - Ok(Descend(true)) + for (field_name, _, field) in fields.iter_all() { + if matches!(subs[field], RecordField::Optional(..)) { + return Err(NotDerivable { + var, + context: NotDerivableContext::Decode(NotDerivableDecode::OptionalRecordField( + subs[field_name].clone(), + )), + }); + } } + + Ok(Descend(true)) } #[inline(always)] diff --git a/crates/reporting/src/error/type.rs b/crates/reporting/src/error/type.rs index e51aea74a9..5f47d40762 100644 --- a/crates/reporting/src/error/type.rs +++ b/crates/reporting/src/error/type.rs @@ -425,7 +425,9 @@ fn underivable_hint<'b>( alloc.reflow("Roc cannot derive decoding for a record with an optional field, which in this case is "), alloc.record_field(field), alloc.reflow(". Optional record fields are polymorphic over records that may or may not contain them at compile time, "), - alloc.reflow("but are not a concept that extends to runtime! That means Roc cannot derive a decoder for a record with an optional value "), + alloc.reflow("but are not a concept that extends to runtime!"), + alloc.hardline(), + alloc.reflow("That means Roc cannot derive a decoder for a record with an optional value "), alloc.reflow("by way of an optional record field. If you want to model the idea that a field may or may not be present at runtime, "), alloc.reflow("consider using a "), alloc.symbol_unqualified(Symbol::RESULT_RESULT),