From 47b5fb7672bf9d3893b83af5b46a28a7791edc7b Mon Sep 17 00:00:00 2001 From: James deBoer Date: Thu, 27 Jun 2013 09:29:58 -0700 Subject: [PATCH] fix(parser): Do not use isInterface. Works around dartbug 9434 --- lib/parser.dart | 57 +++++++++++++++++++++++++------------------ test/parser_spec.dart | 36 +++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/lib/parser.dart b/lib/parser.dart index 3b6e10b84..6117b8c9f 100644 --- a/lib/parser.dart +++ b/lib/parser.dart @@ -144,29 +144,35 @@ getterChild(value, childKey) { } } - if (isInterface(value, Getter) && value.containsKey(childKey)) { - return [true, value[childKey]]; - } else { - InstanceMirror instanceMirror = reflect(value); - Symbol curSym = new Symbol(childKey); - try { - // maybe it is a member field? - return [true, instanceMirror.getField(curSym).reflectee]; - } catch (e) { - // maybe it is a member method? - if (instanceMirror.type.members.containsKey(curSym)) { - MethodMirror methodMirror = instanceMirror.type.members[curSym]; - return [true, _relaxFnArgs((args) { - if (args == null) args = []; - try { - return instanceMirror.invoke(curSym, args).reflectee; - } catch (e) { - throw "$e \n\n${e.stacktrace}"; - } - })]; - } - return [false, null]; + // TODO: replace with isInterface(value, Getter) when dart:mirrors + // can support mixins. + try { + // containsKey() might not return a boolean, so explicitly test + // against true. + if (value.containsKey(childKey) == true) { + return [true, value[childKey]]; } + } on NoSuchMethodError catch(e) {} + + InstanceMirror instanceMirror = reflect(value); + Symbol curSym = new Symbol(childKey); + try { + // maybe it is a member field? + return [true, instanceMirror.getField(curSym).reflectee]; + } catch (e) { + // maybe it is a member method? + if (instanceMirror.type.members.containsKey(curSym)) { + MethodMirror methodMirror = instanceMirror.type.members[curSym]; + return [true, _relaxFnArgs((args) { + if (args == null) args = []; + try { + return instanceMirror.invoke(curSym, args).reflectee; + } catch (e) { + throw "$e \n\n${e.stacktrace}"; + } + })]; + } + return [false, null]; } } @@ -195,10 +201,13 @@ getter(scope, locals, path) { } setterChild(obj, childKey, value) { - if (isInterface(obj, Setter)) { + // TODO: replace with isInterface(value, Setter) when dart:mirrors + // can support mixins. + try { obj[childKey] = value; return value; - } + } on NoSuchMethodError catch(e) {} + InstanceMirror instanceMirror = reflect(obj); Symbol curSym = new Symbol(childKey); try { diff --git a/test/parser_spec.dart b/test/parser_spec.dart index fd794cec9..a102020eb 100644 --- a/test/parser_spec.dart +++ b/test/parser_spec.dart @@ -9,6 +9,22 @@ class TestData { method() => "testMethod"; } +class Mixin {} +class MixedTestData extends TestData with Mixin { +} + +class MapData { + operator[](x) => "mapped-$x"; + containsKey(x) => true; +} +class MixedMapData extends MapData with Mixin { } +class InheritedMapData extends MapData { } + +class BadContainsKeys { + containsKey(x) => null; + String str = "member"; +} + class LexerExpect extends Expect { LexerExpect(actual) : super(actual); toBeToken(int index, String text) { @@ -565,6 +581,26 @@ main() { expect(Parser.parse('str="bob"')(data)).toEqual('bob'); expect(data.str).toEqual("bob"); }); + + it('should support member field getters from mixins', () { + MixedTestData data = new MixedTestData(); + data.str = 'dole'; + expect(Parser.parse('str')(data)).toEqual('dole'); + }); + + it('should support map getters from superclass', () { + InheritedMapData mapData = new InheritedMapData(); + expect(Parser.parse('notmixed')(mapData)).toEqual('mapped-notmixed'); + }); + + it('should support map getters from mixins', () { + MixedMapData data = new MixedMapData(); + expect(Parser.parse('str')(data)).toEqual('mapped-str'); + }); + + iit('should gracefully handle bad containsKey', () { + expect(Parser.parse('str')(new BadContainsKeys())).toEqual('member'); + }); }); describe('assignable', () {